From 35211ee5f32f2f1e645cd0af966309186b830aca Mon Sep 17 00:00:00 2001 From: barreiro Date: Thu, 26 Jan 2017 14:55:24 +0000 Subject: [PATCH] HHH-11426 - NullPointerException in getPersistenceUnitUtil().getIdentifier() on detached enhanced entity --- .../jpa/internal/PersistenceUnitUtilImpl.java | 33 +++++++---- .../bytecode/enhancement/EnhancerTest.java | 7 +++ .../DetachedGetIdentifierTestTask.java | 59 +++++++++++++++++++ 3 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/detached/DetachedGetIdentifierTestTask.java diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java index 378a783d1b..2caf603ebb 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java @@ -11,6 +11,7 @@ import javax.persistence.PersistenceUnitUtil; import javax.persistence.spi.LoadState; import org.hibernate.Hibernate; +import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.ManagedEntity; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.jpa.internal.util.PersistenceUtilHelper; @@ -66,12 +67,18 @@ public class PersistenceUnitUtilImpl implements PersistenceUnitUtil, Serializabl } if ( entity instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) entity; - return proxy.getHibernateLazyInitializer().getIdentifier(); + return ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier(); } else if ( entity instanceof ManagedEntity ) { - final ManagedEntity enhancedEntity = (ManagedEntity) entity; - return enhancedEntity.$$_hibernate_getEntityEntry().getId(); + EntityEntry entityEntry = ((ManagedEntity) entity).$$_hibernate_getEntityEntry(); + if ( entityEntry != null ) { + return entityEntry.getId(); + } + else { + // HHH-11426 - best effort to deal with the case of detached entities + log.debug( "javax.persistence.PersistenceUnitUtil.getIdentifier may not be able to read identifier of a detached entity" ); + return getIdentifierFromPersister( entity ); + } } else { log.debugf( @@ -79,13 +86,17 @@ public class PersistenceUnitUtilImpl implements PersistenceUnitUtil, Serializabl "(although Hibernate also adapts this support to its proxies); " + "however the passed entity was not enhanced (nor a proxy).. may not be able to read identifier" ); - final Class entityClass = Hibernate.getClass( entity ); - final EntityPersister persister = sessionFactory.getMetamodel().entityPersister( entityClass ); - if ( persister == null ) { - throw new IllegalArgumentException( entityClass + " is not an entity" ); - } - //TODO does that work for @IdClass? - return persister.getIdentifier( entity ); + return getIdentifierFromPersister( entity ); } } + + private Object getIdentifierFromPersister(Object entity) { + Class entityClass = Hibernate.getClass( entity ); + EntityPersister persister = sessionFactory.getMetamodel().entityPersister( entityClass ); + if ( persister == null ) { + throw new IllegalArgumentException( entityClass.getName() + " is not an entity" ); + } + return persister.getIdentifier( entity, null ); + } + } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java index be598228c9..42b2a110de 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java @@ -8,6 +8,7 @@ package org.hibernate.test.bytecode.enhancement; import org.hibernate.bytecode.enhance.spi.UnloadedClass; +import org.hibernate.test.bytecode.enhancement.detached.DetachedGetIdentifierTestTask; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; @@ -83,6 +84,12 @@ public class EnhancerTest extends BaseUnitTestCase { EnhancerTestUtils.runEnhancerTestTask( DirtyTrackingTestTask.class ); } + @Test + @TestForIssue( jiraKey = "HHH-11426" ) + public void testDetached() { + EnhancerTestUtils.runEnhancerTestTask( DetachedGetIdentifierTestTask.class ); + } + @Test public void testEviction() { EnhancerTestUtils.runEnhancerTestTask( EvictionTestTask.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/detached/DetachedGetIdentifierTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/detached/DetachedGetIdentifierTestTask.java new file mode 100644 index 0000000000..76a263900e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/detached/DetachedGetIdentifierTestTask.java @@ -0,0 +1,59 @@ +package org.hibernate.test.bytecode.enhancement.detached; + +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Luis Barreiro + */ +public class DetachedGetIdentifierTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[]{SimpleEntity.class}; + } + + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + } + + public void execute() { + EntityManager em = getFactory().createEntityManager(); + em.getTransaction().begin(); + + SimpleEntity se = new SimpleEntity(); + se.name = "test"; + se = em.merge( se ); + + Assert.assertNotNull( getFactory().getPersistenceUnitUtil().getIdentifier( se ) ); + + em.getTransaction().commit(); + em.close(); + + // Call as detached entity + Assert.assertNotNull( getFactory().getPersistenceUnitUtil().getIdentifier( se ) ); + } + + protected void cleanup() { + } + + @Entity + public static class SimpleEntity { + + @Id + @GeneratedValue + private Long id; + + private String name; + + } +}