So I'm developing an API and I'm trying to connect to a local docker instance of DB2 from java using JPA entity manager. After running Apache Maven and getting build success, I try a GET request from Postman to test an endpoint and get a list of all users from DB2. I'm receiving the below error saying that entity manager is null. I've tried researching online and can't seem to find the solution. The Dao class is virtually unchanged from a previous iteration that used Derby instead of DB2 and it worked fine. I was wanting to know where I've gone wrong, what needs changing, and if anything is not needed. Provided below is the xml files and the DAO java class containing the entity manager. All properties for DB2 is correct as they're unchanged from a successful connection I was able to do from Eclipse's Database Development. The driver used then was db2jcc4 which I think is different to the driver said to use for the maven dependency so not sure if that's an issue.
Postman:
Error 500: java.lang.NullPointerException: Cannot invoke "javax.persistence.EntityManager.createNamedQuery(String, java.lang.Class)" because "this.em" is null
Maven:
[INFO] [ERROR ] CWWJP0015E: An error occurred in the org.eclipse.persistence.jpa.PersistenceProvider persistence provider when it attempted to create the container entity manager factory for the jpa-unit persistence unit. The following error occurred: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.7.9.v20210604-2c549e2208): org.eclipse.persistence.exceptions.EntityManagerSetupException
[INFO] Exception Description: Predeployment of PersistenceUnit [jpa-unit] failed.
[INFO] Internal Exception: javax.persistence.PersistenceException: CWWJP0013E: The server cannot locate the java:comp/DefaultDataSource data source for the jpa-unit persistence unit because it has encountered the following exception: javax.naming.NameNotFoundException: javax.naming.NameNotFoundException: java:comp/DefaultDataSource.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.obdoblock</groupId>
<artifactId>hyperledger-api</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- Liberty configuration -->
<liberty.var.default.http.port>3500</liberty.var.default.http.port>
<liberty.var.default.https.port>9443</liberty.var.default.https.port>
<liberty.var.app.context.root>api</liberty.var.app.context.root>
<!-- TestDB Configuration -->
<version.ibm.db2>11.5.6.0</version.ibm.db2>
</properties>
<dependencies>
<!-- Provided dependencies -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>8.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>3.3</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<!-- For tests -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.3.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.3.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.7</version>
<scope>test</scope>
</dependency>
<!-- DB2 connector -->
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>11.5.6.0</version>
</dependency>
<!-- Hyperledger Fabric Gateway for Blockchain -->
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- Enable liberty-maven plugin -->
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<version>3.3.4</version>
<configuration>
<copyDependencies>
<location>${project.build.directory}/liberty/wlp/usr/shared/resources</location>
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>11.5.6.0</version>
</dependency>
</copyDependencies>
</configuration>
</plugin>
<!-- Plugin to run functional tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<systemPropertyVariables>
<http.port>${liberty.var.default.http.port}</http.port>
<context.root>${liberty.var.app.context.root}</context.root>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
<!-- Plugin to run unit tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
server.xml
<server description="Obdoblock REST Server">
<featureManager>
<feature>jaxrs-2.1</feature>
<feature>openapi-3.1</feature>
<feature>jpa-2.2</feature>
<feature>cdi-2.0</feature>
</featureManager>
<httpEndpoint
httpPort="${default.http.port}"
httpsPort="${default.https.port}"
id="defaultHttpEndpoint"
host="*"
/>
<webApplication
location="hyperledger-api.war"
contextRoot="${app.context.root}"
/>
<!-- DB2 Library Configuration -->
<library id="DB2JCCLib">
<fileset dir="${shared.resource.dir}" includes="*.jar" />
</library>
<dataSource jndiName="jdbc/db2">
<jdbcDriver libraryRef="jdbcLib"/>
<properties
databaseName="testdb"
serverName="localhost"
portNumber="50000"
user="****" password="****"
/>
</dataSource>
</server>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- TODO: This will have to be configured by ENV as well -->
<!-- https://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/p_ddl_generation.htm -->
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="jpa-unit" transaction-type="JTA">
<properties>
<!-- Connection Specific -->
<property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect"/>
<property name="javax.persistence.jdbc.driver" value="com.ibm.db2.jcc.DB2Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:db2://localhost:50000/testdb" />
<property name="javax.persistence.jdbc.user" value="****" />
<property name="javax.persistence.jdbc.password" value="****" />
<property name="show_sql" value="true"/>
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
</properties>
</persistence-unit>
</persistence>
UserDao.java
package dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.enterprise.context.RequestScoped;
import models.*;
@RequestScoped
public class UserDao {
@PersistenceContext(name = "jpa-unit")
private EntityManager em;
public void createUser(Users user){
em.persist(user);
}
public Users readUser(int userId){
return em.find(Users.class, userId);
}
public List<Users> readAllUsers(){
return em.createNamedQuery("Users.findAll", Users.class).getResultList();
}
public void updateUser(Users user){
em.merge(user);
}
public void deleteUser(Users userId){
em.remove(userId);
}
public List<Users> findUser(String email){
return em.createNamedQuery("Users.findUser", Users.class)
.setParameter("email", email)
.getResultList();
}
public void createHistory(History hist){
em.persist(hist);
}
//wait this doesnt do anything?
public Users readHistory(int id){
return em.find(Users.class, id);
}
public List<History> readAllHistory(){
return em.createNamedQuery("History.findAll", History.class).getResultList();
}
}
Versions:
- Docker: 20.10.8, build 3967b7d
- DB2: ibm/db2 docker image version 11.5.6
- Maven: 3.8.3
- Java: JDK 14.0.2
If needing any more details, I'm happy to provide them. Thanks, Dylan
CodePudding user response:
Your persistence.xml
is incorrect. It should point to datasource configured in the server.xml
, not specify driver properties.
Like this:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="jpa-unit" transaction-type="JTA">
<jta-data-source>jdbc/guestbookDS</jta-data-source>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create" />
<property name="javax.persistence.schema-generation.create-database-schemas" value="true" />
<property name="javax.persistence.schema-generation.scripts.action" value="create" />
<property name="javax.persistence.schema-generation.scripts.create-target" value="create.ddl"/>
<!--
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="both" />
-->
</properties>
</persistence-unit>
</persistence>
You can check this very simple Liberty project which uses JPA and database here https://github.com/stocktrader-ops/db-sat-demo (it is using PostgreSQL instead of DB2, but you should just use your datasource setup)