Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error related with JPA EntityGraph in Spring Boot 3.4.0 #3709

Closed
dimcookies opened this issue Dec 10, 2024 · 1 comment
Closed

Error related with JPA EntityGraph in Spring Boot 3.4.0 #3709

dimcookies opened this issue Dec 10, 2024 · 1 comment
Labels
for: external-project For an external project and not something we can fix

Comments

@dimcookies
Copy link

Summary:
I originally posted this as a Spring Boot issue, but since this is JPA/Hibernate related, maybe it belongs here.
After upgrading to Spring Boot 3.4.0 (Hibernate 6.6.2-Final), there is a Hibernate related error when a transactional method, after saving a row, tries to retrieve some data from a repository method using EntityGraph. This worked in Spring Boot 3.3.5 (Hibernate 6.5.3-Final). As it is mentioned in the original issue, this has to do with using non-managed objects but it is almost impossible to identify all the cases, so i trying to check if there is a way to get the functionality in the previous version (without downgrading hibernate)

Details:
TestController calls addPayment from TestService1. This method is transactional.
This method calls the save() method of a repository
Then it calls another service TestService2 method2

This method performs a query using a repository and then another query from another repository which uses EntityGraph.

The exception is

2024-12-09T19:04:46.304+02:00 ERROR 24764 --- [errorCheck] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.spi.EntityEntry.getMaybeLazySet()" because "entityEntry" is null] with root cause

java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.spi.EntityEntry.getMaybeLazySet()" because "entityEntry" is null
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstanceSubInitializers(EntityInitializerImpl.java:625) ~[hibernate-core-6.6.2.Final.jar:6.6.2.Final]
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstance(EntityInitializerImpl.java:988) ~[hibernate-core-6.6.2.Final.jar:6.6.2.Final]
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstance(EntityInitializerImpl.java:97) ~[hibernate-core-6.6.2.Final.jar:6.6.2.Final]

While trying to reproduce the issue i got another exception, but not constantly

an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session

If we change the version of Spring Boot to 3.3.5, this works

Steps to reproduce:

  1. Run the attached project using postgres as database.
    errorCheck.zip

  2. Access "http://localhost:8080/test" and an exception will be produced

2024-12-09T19:04:46.304+02:00 ERROR 24764 --- [errorCheck] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.spi.EntityEntry.getMaybeLazySet()" because "entityEntry" is null] with root cause

If we change the Spring Boot version to 3.3.5 the endpoint will return the response "1"

Environment:
Spring Boot version: 3.4.0
Java version: 21
Operating System: Windows 11

Attachments
Sample project to reproduce the error

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 10, 2024
@mp911de
Copy link
Member

mp911de commented Dec 10, 2024

This looks pretty much like a bi-directional mapping issue StudentFeesToInvoice.invoice.payments -> Invoice -> payments -> Invoice.

This method should only be called if the entity is already initialized

	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstanceSubInitializers(EntityInitializerImpl.java:614)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstance(EntityInitializerImpl.java:988)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstance(EntityInitializerImpl.java:97)
	at org.hibernate.sql.results.graph.Initializer.resolveInstance(Initializer.java:149)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstanceSubInitializers(EntityInitializerImpl.java:662)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:589)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:453)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:97)
	at org.hibernate.sql.results.graph.Initializer.resolveKey(Initializer.java:101)
	at org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer.resolveKeySubInitializers(AbstractImmediateCollectionInitializer.java:189)
	at org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer.resolveCollectionContentKey(AbstractImmediateCollectionInitializer.java:176)
	at org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer.resolveInstance(AbstractImmediateCollectionInitializer.java:382)
	at org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer.resolveInstance(AbstractImmediateCollectionInitializer.java:42)
	at org.hibernate.sql.results.graph.Initializer.resolveInstance(Initializer.java:149)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveInstanceSubInitializers(EntityInitializerImpl.java:662)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:589)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:453)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:97)
	at org.hibernate.sql.results.graph.Initializer.resolveKey(Initializer.java:101)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKeySubInitializers(EntityInitializerImpl.java:696)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:601)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:453)
	at org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.resolveKey(EntityInitializerImpl.java:97)
	at org.hibernate.sql.results.internal.StandardRowReader.coordinateInitializers(StandardRowReader.java:235)
	at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:141)
	at org.hibernate.sql.results.spi.ListResultsConsumer.readUnique(ListResultsConsumer.java:283)
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:195)
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:35)
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:224)
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:102)
	at org.hibernate.sql.exec.spi.JdbcSelectExecutor.executeQuery(JdbcSelectExecutor.java:91)
	at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:165)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$1(ConcreteSqmSelectQueryPlan.java:152)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:442)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:362)
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:380)
	at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:143)
	at org.hibernate.query.Query.getResultList(Query.java:120)

I can reproduce the issue with the following JPA code:

long userId = 1;

Payment payment = new Payment();

var invoice = new Invoice();
invoice.setId(1L);
payment.setInvoice(invoice);

AppUser appUser = new AppUser();
appUser.setId(userId);
payment.setCreatedFrom(appUser);

entityManager.persist(payment);

Invoice invoiceLoaded = (Invoice) entityManager.createQuery("SELECT i FROM Invoice i WHERE i.id = ?1")
		.setParameter(1, invoice.getId()).getSingleResult();

jakarta.persistence.EntityGraph<StudentFeesToInvoice> entityGraph = entityManager
		.createEntityGraph(StudentFeesToInvoice.class);
entityGraph.addSubgraph("invoice")
		.addSubgraph("payments")
		.addAttributeNodes("createdFrom");

// failure happens here
entityManager.createQuery("SELECT s FROM StudentFeesToInvoice s WHERE id = ?1")
		.setHint("jakarta.persistence.fetchgraph", entityGraph)
		.setParameter(1, invoiceLoaded.getId()).getResultList();

I don't think that Hibernate can do much especially when being told to use eager fetching instead of lazy-loading proxies. In any case, please file a bug report with the Hibernate issue tracker as the NullPointerException should be guarded properly.

@mp911de mp911de closed this as not planned Won't fix, can't repro, duplicate, stale Dec 10, 2024
@mp911de mp911de added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

3 participants