I encountering a problem when sending a GET request from Postman to test my endpoints. The same NamedQueries worked before with Derby with just the one Schema, so no need to differentiate then. I have now changed to DB2 running in a local Docker instance and am using Maven to run Open-Liberty Framework to create the endpoints. I am receiving the below error. Do I need to create a orm.xml file with entity-mappings, or do something else to resolve this? I would prefer to do this without more xml files if possible.
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-28019] (Eclipse Persistence Services - 2.7.9.v20210604-2c549e2208): org.eclipse.persistence.exceptions.EntityManagerSetupException
[INFO] Exception Description: Deployment of PersistenceUnit [jpa-unit] failed. Close all factories for this PersistenceUnit.
[INFO] Internal Exception: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.7.9.v20210604-2c549e2208): org.eclipse.persistence.exceptions.JPQLException
[INFO] Exception Description: Problem compiling [SELECT u FROM Sankofa.Users u].
[INFO] [14, 29] 'Sankofa.Users u' cannot be the first declaration of the FROM clause.
UserDao
package dao;
import java.util.List;
import java.util.concurrent.TimeoutException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hyperledger.fabric.gateway.ContractException;
import javax.enterprise.context.RequestScoped;
import models.*;
@RequestScoped
public class UserDao {
//DB2 Methods
@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);
}
//NEED TO DO set return limit to 20
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 userID){
return em.find(Users.class, userID);
}
public List<History> readAllHistory(){
return em.createNamedQuery("History.findAll", History.class).getResultList();
}
}
Users
package models;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.persistence.*;
import java.time.LocalDate;
@Entity
@Table(name = "Users")
@NamedQueries({
@NamedQuery(name = "Users.findAll", query = "SELECT u FROM Users u"),
@NamedQuery(name = "Users.findUser", query = "SELECT usr FROM Users usr WHERE usr.email = :email")
})
public class Users {
private static JsonObjectBuilder builder = Json.createObjectBuilder();
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
@Column(name = "userId")
private int id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
@Column(name = "gender")
private String gender;
@Column(name = "address")
private String address;
@Column(name = "email")
private String email;
@Column(name = "password")
private String password;
@Column(name = "dateOfBirth")
private LocalDate dateOfBirth;
Persistence.xml
<?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">
<mapping-file>orm.xml</mapping-file>
<properties>
<!-- Connection Specific -->
<property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect"/>
<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"/>
</properties>
</persistence-unit>
</persistence>
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">
<file name="${shared.resource.dir}/jcc-11.5.6.0" />
</library>
<dataSource id="DefaultDataSource" jndiName="jdbc/db2">
<jdbcDriver libraryRef="jdbcLib"/>
<properties.db2.jcc
databaseName="testdb"
serverName="localhost"
portNumber="50000"
user="****" password="****"
/>
</dataSource>
</server>
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:
How to specify tables from different DB2 schemas using @NamedQuery
AFAIK, you cannot configure the schema value at the query level. All the named queries defined under the Entity at expected to be executed against the same schema.
The database schema can be set at the persistence-unit level via orm.xml mapping file:
orm.xml
<entity-mappings ... > <persistence-unit-metadata> <persistence-unit-defaults> <schema>Sankofa</schema> </persistence-unit-defaults> </persistence-unit-metadata> . . . </entity-mappings>
persistence.xml
<persistence ... > <persistence-unit name="foo"> <mapping-file>orm.xml</mapping-file> </persistence-unit> </persistence>
For EclipseLink, you can configure a SessionCustomizer class
public class FooSessionCustomizer implements org.eclipse.persistence.config.SessionCustomizer { @Override public void customize(Session session) throws Exception { session.getLogin().setTableQualifier("Sankofa"); } }
persistence.xml
<persistence ... > <persistence-unit name="foo"> <properties> <property name="eclipselink.session.customizer" value="foo.customizer.FooSessionCustomizer" /> </properties> </persistence-unit> </persistence>
The @Table annotation has a "schema" element to configure the schema at the Entity level
@Table(name = "Users", schema = "Sankofa")