Exception Description: A NullPointerException - java

I'm working on a project in java with a postgresql database and I'm having a problem when I try to insert data or rather when I commit.
It looks like it comes from a problem with ID (game_id) but I do not know what.
Here is the code of my entity :
#Entity
#Cacheable(true)
#Table(name = "game")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
public class Game implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "game_id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer gameId;
#Column(name = "game_title", length = 256)
private String gameTitle;
#Temporal(TemporalType.DATE)
#Column(name = "game_released")
private Date gameReleased;
#Column(name = "game_img")
private Byte[] gameImg;
#Column(name = "game_desc", length = 3072)
private String gameDesc;
And here's how I try to insert my data :
EntityManagerFactory emf = Persistence.createEntityManagerFactory("projet_nintendo");
EntityManager em = emf.createEntityManager();
EntityTransaction transac = em.getTransaction();
transac.begin();
for(int ii = 0; ii < array.length(); ii++) {
Game g = new Game();
g.setGameId(Conversion.stringEnInt(array.getJSONObject(ii).getString("fs_id")));
g.setGameTitle(array.getJSONObject(ii).getString("title"));
JSONArray test = array.getJSONObject(ii).getJSONArray("dates_released_dts");
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
Date parsedDate = dateFormat.parse(test.getString(0));
g.setGameReleased(parsedDate);
} catch(Exception e) {
}
em.persist(g);
System.err.println(array.getJSONObject(ii).getString("pretty_date_s"));
}
transac.commit();
em.close();
emf.close();
I have this error :
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-69] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: A NullPointerException was thrown while extracting a value from the instance variable [gameId] in the object [database.orm.Game].
Internal Exception: java.lang.NullPointerException
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[gameId-->game.game_id]
Descriptor: RelationalDescriptor(database.orm.Game --> [DatabaseTable(game)])
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157)
at test.main(test.java:79)
Caused by: Exception [EclipseLink-69] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd)
Could you tell me what I'm doing wrong?

try(EntityManager em = emf.createEntityManager();
EntityTransaction transac = em.getTransaction()){
...
}
// don't need to close here em.. emf..

Try to remove your #GeneratedValue. Currently you are using
GenerationType.IDENTITY
This GenerationType indicates that the persistence provider must assign primary keys for the entity using a database identity column. IDENTITY column is typically used in SQL Server. This special type column is populated internally by the table itself without using a separate sequence. If underlying database doesn't support IDENTITY column or some similar variant then the persistence provider can choose an alternative appropriate strategy. In this examples we are using H2 database which doesn't support IDENTITY column.
This results in the database assigns a new value automatically for your id field and then EclipseLink have to retrieve it.

Related

Many-To-One Association in Spring JPA does not update related entity

I have a problem inserting JPA entites in the DB using a many-to-one association.
I'm using:
Spring Boot 2.1.4.RELEASE
Ecliselink 2.7.4.RC2 (org.eclipse.persistence.jpa)
spring-boot-starter-data-jpa
I'm using Spring's repository where I only have a save method and no insert, merge or update methods.
I use an entity DbWatchlist which has a many-to-one association to another entity DbWatchlistProvider.
If I create a new DBWatchlist with the fields for DbWatchlistProvider filled everything works fine. Also if I change an existing DbWatchlist and also here the fields for DbWatchlistProvider and do a save everything works.
But if I try to create a new DbWatchlist with an existing DbWatchlistProvider JPA always tries to INSERT a new record for DbWatchlistProvider.
I tried to read the DbWatchlistProvider from the database before inserting into the entity DbWatchlist and after that do a save, but also here an INSERT is done. This results in a exception:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER
Error Code: -104
Call: INSERT INTO WatchlistProvider (Key, Description, Id) VALUES (?, ?, ?)
bind => [3 parameters bound]
My code:
#Entity
#Table(name = TableName.WATCHLIST, uniqueConstraints = {
#UniqueConstraint(columnNames = {ColumnName.PROVIDER_KEY, ColumnName.ID})})
#UuidGenerator(name = KEY_GENERATOR)
public class DbWatchlist {
#Id
#Column(name = ColumnName.KEY, nullable = false)
#GeneratedValue(generator = KEY_GENERATOR)
public String key;
#ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = ColumnName.PROVIDER_KEY, nullable = false, updatable = false)
public DbWatchlistProvider watchlistProvider;
#Column(name = ColumnName.ID, nullable = false)
public String id;
#Column(name = ColumnName.DESCRIPTION)
public String description;
#Column(name = ColumnName.LATEST_VERSION)
public String latestVersion;
}
#Entity
#Table(name = TableName.PROVIDER, uniqueConstraints = {
#UniqueConstraint(columnNames = {ColumnName.ID})})
#UuidGenerator(name = KEY_GENERATOR)
public class DbWatchlistProvider {
#Id
#Column(name = ColumnName.KEY, nullable = false)
#GeneratedValue(generator = KEY_GENERATOR)
public String key;
#Column(name = ColumnName.ID, nullable = false)
public String id;
#Column(name = ColumnName.DESCRIPTION)
public String description;
}
#Repository
public interface WatchlistRepository extends CrudRepository<DbWatchlist, String> {
boolean existsByWatchlistProviderAndId(DbWatchlistProvider provider, String id);
}
In my test I tried the following:
DbWatchlistProvider provider = new DbWatchlistProvider();
provider.id = "PROV";
provider.description = "description for provider";
DbWatchlist newRow = new DbWatchlist();
newRow.id = "ID1";
newRow.description = "description";
newRow.watchlistProvider = provider;
DbWatchlist createdRow = repository.save(newRow);
createdRow.description = "update";
createdRow.watchlistProvider.description = "also updated";
createdRow = repository.save(createdRow);
DbWatchlist createdRow2 = new DbWatchlist();
createdRow2.watchlistProvider = createdRow.watchlistProvider;
createdRow2.id = "test";
createdRow2.description = "description";
//This save is not working, but the createdRow2.watchlistProvider.key is filled
repository.save(createdRow2);
Till the last save everything is working without errors and like expected.
Has someone any idea what is the problem and why the DbWatchlistProvider is trying to be inserted and not updated?
Exception is:
Caused by: javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER
Error Code: -104
Call: INSERT INTO WatchlistProvider (Key, Description, Id) VALUES (?, ?, ?)
bind => [3 parameters bound]
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException
Query: InsertObjectQuery
Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER
Caused by: org.hsqldb.HsqlException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER
I've been having the same issue, and recently found out the base cause.
In my case, the problem was that I had two #Entity classes referencing the same #Table(name = X)
When you have such a thing happening, you have to update both entities at the same time, or else you get errors like you're seeing here.
The solution (in my case) is to use a DTO Projection instead of having a duplicate entity for the one table.
Simple fix, but the error causes way more confusion than clarity.
No idea if you've got the same problem or not, but you do have the same error.
HTH!

Representing #EmbeddedId as SQL for H2 database

I am currently working on a Java project with Hibernate entities (more below). In order to test my data access object layers, I am using H2 database to populate an in-memory database and throwing queries at it. Until this point, everything is fine.
However, the problem comes when simulating the #EmbeddedId annotation.
#Entity
#Table(name = "BSCOBJ")
public class BasicObject extends AbstractDomainObject {
#EmbeddedId // This annotation here
private RestrainPK restrain;
#Embeddable
public static class RestrainPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "CODI", nullable = false)
private String coDi;
#Column(name = "COGA", nullable = false)
private String coGa;
#Column(name = "TYOR", nullable = false)
private String tyOr;
public RestrainPK() {
}
... // Getters and setters
}
}
"Simply" creating the table BSCOBJ and populating it gives no value when fetching data (of course, I checked that the request would give result "normally"). How do I represent this nested class in a SQL table creation / value insertion request ? Is that even possible ?
Thanks in advance,
EDIT
As requested, here is some samples about the SQL / Hibernate ran.
Creation request:
CREATE TABLE BSCOBJ (CODI VARCHAR(5) NOT NULL, COGA VARCHAR(5) NOT NULL, TYOR VARCHAR(5) NOT NULL);
Insertion request:
INSERT INTO BSCOBJ (CODI, COGA, TYOR) VALUES
('HELLO', 'MAT', 'REF'),
('BONJ', 'SOME', 'DAIL'),
('SOPA', 'KDA', 'RATIO');
Request given by Hibernate when trying to run the test code:
select r.restrain.tyOr from mypackage.BasicObject r where r.restrain.coDi = :coDi and r.restrain.coGa = :coGa
With the following values:
coDi = "BONJ";
coGa = "SOME";
Throws a NoResultException. I am expecting DAIL, from the second line of the INSERT request.
I have used #EmbeddedId only one time, but I think that you need #AttributeOverrides under your #EmbeddedId
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "idpk", column = #Column(name="IDPK", nullable = false),
#AttributeOverride(name = "code", column = #Column(name="CODE")
})
and remove your #Column annotations from FormulePK

The duplicate key value JPA

I have build a small application on SPring MVC + JPA + SQL Server. For some reasons I had to make some Entity changes in my application and I had to manually migrate some data from old Database to new Database(that have a bit different schema). After I migrated all the data I have such errors:
13:47:26.191 [http-nio-8080-exec-1] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Violation of PRIMARY KEY constraint 'PK__GLJourna__3213E83F741BD595'. Cannot insert duplicate key in object 'dbo.GLEntry'. The duplicate key value is (34903).
This is my entity:
#Entity
public class GLJournalEntry {
#Id #GeneratedValue
private Long id;
private BigDecimal amount;
private Date creationDate;
#OneToOne
#JoinColumn(name = "glAccount_id", nullable = false)
private GLAccount glAccount;
private String notes;
#Enumerated(EnumType.STRING)
private ProductType productTyep;
private Date entryDate;
#Column(nullable = false)
private long transactionID;
#Enumerated(EnumType.STRING)
private EntryType type;
}
My guess is that I receive this error message because of default ID annotation #Id #GeneratedValue.
How can I fix it? how can I generate ID in a way that it automatically got the latest ID from DB?
The easiest solution to my problem was to change annotation to the Entity
Changed from :
#Id #GeneratedValue
to:
#Id #GeneratedValue(strategy = GenerationType.AUTO)
Try something like this in your Database
CREATE SEQUENCE "ABC"."MY_SEQ" MINVALUE 0 MAXVALUE 2147483647 INCREMENT BY 1 START WITH 9130 CACHE 50 ORDER NOCYCLE ;
You can get latest Id from DB by using custom logic. Sample what I did to resolve my issue. It works with Hibernate -
#Id
#Basic(optional = false)
#GeneratedValue(strategy=GenerationType.IDENTITY, generator="GeneratedId")
#GenericGenerator(name="GeneratedId",
strategy="....GenerateId"
)
#Column(name = "ID", nullable = false)
private Integer id;
and
import org.hibernate.id.IdentityGenerator;
...
public class GenerateId extends IdentityGenerator {
private static final Logger log = Logger.getLogger(GenerateId.class.getName());
#Override
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
String prefix = "M";
Connection connection = session.connection();
try {
PreparedStatement ps = connection
.prepareStatement("SELECT nextval ('seq_stock_code') as nextval");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("nextval");
String code = prefix + StringUtils.leftPad("" + id,3, '0');
log.debug("Generated Stock Code: " + code);
return code;
}
} catch (SQLException e) {
log.error(e);
throw new HibernateException(
"Unable to generate Stock Code Sequence");
}
return null;
}
You can use sequence functionality of the db to get unique ID, which will always be the new and latest one.
Use the link for more informations http://stackoverflow.com/questions/2595124/java-jpa-generators-sequencegenerator

How to find/change hibernate query

I'm trying to fix a bug caused by a Hibernate query on my DB, but i can't seem to find where does the query comes from. After enabling sql log on hibernate i found where the error is, but don't know how to fix.
Hibernate query (eclipse log)
"update students_classes set student_id=null where student_id=?"
throwing:
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8080-2) Column 'student_id' cannot be null
The error is thrown at this line:
student = studentDAO.save(student);
where save comes from
public Entity save(Entity entity) throws Exception {
Entity result = null;
try {
trimAllStrAttributes(entity);
result = em.merge(entity);
} catch (Exception e) {
logger.error("Exception in AbstractDAO", e);
throw e;
}
return result;
}
private void trimAllStrAttributes(Entity product) throws IntrospectionException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
final Class c = product.getClass();
for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
if (method != null) {
String name = method.getName();
// If the current level of Property is of type String
if (method.getReturnType().equals(String.class)) {
String property = (String) method.invoke(product);
if (property != null) {
try {
Method setter = c.getMethod("set" + name.substring(3), new Class<?>[] { String.class });
if (setter != null) {
setter.invoke(product, property.trim());
}
} catch (NoSuchMethodException nsme) {
}
}
}
}
}
}
It can be a mapping problem, so here's my entities:
StudentClasses
#Column(name = "student_id")
private Long studentId;
#Column(name = "classes_id")
private Long classesId;
Student
#AuditJoinTable
#ManyToMany
#JoinTable(name = "students_classes",
joinColumns = #JoinColumn(name = "student_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "classes_id", referencedColumnName = "id"))
private List<Classes> classes;
#NotAudited
#OneToMany
#JoinColumn(name = "student_id")
private List<StudentClasses> studentsClasses;
What should i do? Change hibernate's query (where to find it?) or is there a problem at the mapping level?
Error explains itself:
throwing: ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8080-2) Column 'student_id' cannot be null
As per your other mappings I can say for sure studentId is the primary key of the table, so, if you don't know the id new entities must have, you must mark the field to make hibernate map it:
Mark studentId as id and add an autogenerated value:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long studentId;
Hibernate defines five types of identifier generation strategies:
AUTO - either identity column, sequence or table depending on the underlying DB
TABLE - table holding the id
IDENTITY - identity column
SEQUENCE - sequence
identity copy – the identity is copied from another entity
The problem is with the sequence creation configuration for the StudentId primary key. You have to do two things here.
Create a sequence in the database like below..
CREATE SEQUENCE STUDENT_SEQ
MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
Specify the sequence name in the hibernate configuration.
#Id
#SequenceGenerator(name = "StudentSeq", sequenceName="STUDENT_SEQ", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "StudentSeq")
#Column(name = "Student_id", nullable = false)
private Long StudentId;
My first guess would be, that in this line
result = em.merge(entity);
the entity object does not have a set studentId property, an that causes the exception. So you need to set it yourself, or generate it automatically, as an other answer suggests.

Random LazyInitializationException with #OneToMany

I have a legacy database with the following Tables:
Police
id (PK)
data...
Contract
id(PK)
version(PK)
type
Code
tab(PK)
code(PK)
name
I have a jpa Entity Police
#Entity
public class Police implements Serializable {
#Id
private long id
#OneToMany(fetch = FetchType.LAZY)
#JoinColumns(value = { #JoinColumn(name = "id", referencedColumnName = "id") })
private Set<Contract> contracts;
}
the Contract entity looks like this:
#Entity
public class Contract implements Serializable {
#Id
private long id;
#Id
private long version;
private String type;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumns({ #JoinColumn(name = "code", referencedColumnName = "type") })
#Where(clause = "tab = 'Type'")
private Set<Code> type;
}
Code:
#Entity
public class Code implements Serializable {
#Id
private String tab;
#Id
private String code;
private String name;
}
In the Code table are many different key/values for different applications.
In my case i need the one, where the "tab = 'Type'" and code = type from my Contract.
My Problem is, that if i have more than one Contract for my police, I RANDOMLY? get a org.hibernate.LazyInitializationException.
In my testcase, I do the following:
public static void main(String[] args) {
int countErrors = 0;
for (int i = 0; i < 15; i++) {
try {
readPolice();
} catch (Exception e) {
e.printStackTrace();
countErrors++;
}
}
System.err.println("errors: " + countErrors);
}
private static void readPolice() throws Exception {
EntityManagerFactory factory = EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE);
EntityManager em = factory.createEntityManager();
TypedQuery<Police> namedQuery = em.createNamedQuery(...);
Police result = namedQuery.getSingleResult();
Set<Contract> contracts = result.getContract();
Contract contract = contracts.iterator().next();
Set<Code> type = contract.getType(); //should be a set with one Entry
System.out.println(type.size()); //<--- Chance for Exception!!
em.close();
}
I try this whole thing in a loop 15 times.
In about 5-8 tries, i get the LazyInitializationException.
The other times it works.
Any thoughts about this? Why doesn't it fail all the time?
Just encountered this one. The key word being 'random'. One of my colleagues encountered this exception consistently on her laptop while I never encountered the same. She could reproduce the exception only on IE & Edge.
Finally realized it had to do with Tomcat versions. She was running an older version, while I had a later version - 8.5.8. She upgraded the local Tomcat to this version and the exception is no more encountered.
Make sure the code with println is in the transaction.
LazyInitializationException means that you have loaded entity in some transaction, stepped out of it and then tried to use some lazy-loaded property of this entity.
since your whole code is not here, i assume your name query is not always returning the same entity and when the entity returned contains some Code it trows error.
your transaction must be closed cause otherwise u will not receive lazy initialyzing problem.
You should check that the creation of EntityManagerFactory is executed only once. For example:
public static void main(String[] args) {
EntityManagerFactory emf = EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE);
for (int i = 0; i < 15; i++) {
readPolice(emf);
}
}
private static void readPolice(EntityManagerFactory emf) throws Exception {
EntityManager em = emf.createEntityManager();
...
}
If you're using some kind of singleton pattern in EntityManagerFactoryHelper.getFactory(), make sure it is thread safe.
You can also try to wrap readPolice() inside a transaction by calling em.getTransaction().begin() and em.getTransaction().commit(). For example:
private static void readPolice(EntityManagerFactory emf) throws Exception {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
...
em.getTransaction().commit();
em.close();
}
If I override the equals/hashcode in the Contract entity it works.
Why the problem occured randomly ... I don't get it ...

Categories