Fix issue with Hibernate proxy

This commit is contained in:
Andrea Boriero 2021-12-09 11:59:03 +01:00 committed by Andrea Boriero
parent d845f4b066
commit f765eb4a87
7 changed files with 70 additions and 22 deletions

View File

@ -51,6 +51,8 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
// per-row state
private Object collectionValueKey;
private boolean isInitialized;
public AbstractImmediateCollectionInitializer(
NavigablePath collectionPath,
PluralAttributeMapping collectionAttributeMapping,
@ -272,7 +274,7 @@ protected Object getCollectionValueKey() {
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( responsibility == null ) {
if ( responsibility == null || isInitialized ) {
return;
}
@ -297,6 +299,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
loadingState -> readCollectionRow( collectionKey, loadingState, rowProcessingState )
);
}
isInitialized = true;
}
protected abstract void readCollectionRow(
@ -311,6 +314,7 @@ public void finishUpRow(RowProcessingState rowProcessingState) {
collectionValueKey = null;
collectionInstance = null;
responsibility = null;
isInitialized = false;
}
}

View File

@ -91,6 +91,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
private Object entityInstance;
private Object entityInstanceForNotify;
private boolean missing;
boolean isInitialized;
private boolean isOwningInitializer;
private Object[] resolvedEntityState;
@ -580,7 +581,7 @@ private Object resolveInstance(
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( missing ) {
if ( missing || isInitialized ) {
return;
}
@ -611,6 +612,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
}
notifyResolutionListeners( entityInstanceForNotify );
isInitialized = true;
}
private void initializeEntity(
@ -913,6 +915,7 @@ public void finishUpRow(RowProcessingState rowProcessingState) {
entityInstanceForNotify = null;
missing = false;
resolvedEntityState = null;
isInitialized = false;
clearResolutionListeners();
}
}

View File

@ -49,6 +49,8 @@ public class BatchEntitySelectFetchInitializer extends AbstractFetchParentAccess
private Map<EntityKey, Object> toBatchLoad = new LinkedHashMap<>();
private boolean isInitialized;
public BatchEntitySelectFetchInitializer(
FetchParentAccess parentAccess,
ToOneAttributeMapping referencedModelPart,
@ -84,6 +86,10 @@ public void resolveInstance(RowProcessingState rowProcessingState) {
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( isInitialized ) {
return;
}
if ( !isAttributeAssignableToConcreteDescriptor() ) {
return;
}
@ -142,6 +148,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
toBatchLoad.put( entityKey, parentAccess.getInitializedInstance() );
isInitialized = true;
}
protected boolean isAttributeAssignableToConcreteDescriptor() {
@ -163,6 +170,7 @@ protected boolean isAttributeAssignableToConcreteDescriptor() {
public void finishUpRow(RowProcessingState rowProcessingState) {
entityInstance = null;
clearResolutionListeners();
isInitialized = false;
}
@Override

View File

@ -24,6 +24,7 @@
public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchInitializer {
private final ToOneAttributeMapping fetchedAttribute;
public EntitySelectFetchByUniqueKeyInitializer(
FetchParentAccess parentAccess,
ToOneAttributeMapping fetchedAttribute,
@ -36,16 +37,18 @@ public EntitySelectFetchByUniqueKeyInitializer(
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance != null ) {
if ( entityInstance != null || isInitialized ) {
return;
}
if ( !isAttributeAssignableToConcreteDescriptor() ) {
isInitialized = true;
return;
}
final Object entityIdentifier = identifierAssembler.assemble( rowProcessingState );
if ( entityIdentifier == null ) {
isInitialized = true;
return;
}
final String entityName = concreteDescriptor.getEntityName();
@ -78,5 +81,6 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance != null ) {
entityInstance = persistenceContext.proxyFor( entityInstance );
}
isInitialized = true;
}
}

View File

@ -46,6 +46,7 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
protected final EntityPersister concreteDescriptor;
protected final DomainResultAssembler identifierAssembler;
private final ToOneAttributeMapping referencedModelPart;
protected boolean isInitialized;
protected Object entityInstance;
@ -93,7 +94,7 @@ public void resolveInstance(RowProcessingState rowProcessingState) {
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance != null ) {
if ( entityInstance != null || isInitialized ) {
return;
}
@ -104,6 +105,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
final Object entityIdentifier = identifierAssembler.assemble( rowProcessingState );
if ( entityIdentifier == null ) {
isInitialized = true;
return;
}
@ -123,6 +125,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
entityInstance = persistenceContext.getEntity( entityKey );
if ( entityInstance != null ) {
isInitialized = true;
return;
}
@ -140,6 +143,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
}
initializer.resolveInstance( rowProcessingState );
entityInstance = initializer.getInitializedInstance();
isInitialized = true;
return;
}
@ -173,6 +177,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
}
// EARLY EXIT!!!
isInitialized = true;
return;
}
}
@ -205,6 +210,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance instanceof HibernateProxy ) {
( (HibernateProxy) entityInstance ).getHibernateLazyInitializer().setUnwrap( unwrapProxy );
}
isInitialized = true;
}
protected boolean isAttributeAssignableToConcreteDescriptor() {
@ -225,7 +231,7 @@ protected boolean isAttributeAssignableToConcreteDescriptor() {
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
entityInstance = null;
isInitialized = false;
clearResolutionListeners();
}

View File

@ -23,6 +23,7 @@
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.UniqueKeyLoadable;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.BiDirectionalFetch;
@ -235,7 +236,8 @@ public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourcePr
final Object proxy = persistenceContext.getProxy( entityKey );
// it is conceivable there is a proxy, so check that first
if ( proxy == null ) {
if ( proxy == null || !( proxy.getClass()
.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass().getClass() ) ) ) {
// otherwise look for an initialized version
return persistenceContext.getEntity( entityKey );
}
@ -247,7 +249,16 @@ public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourcePr
initializer.resolveKey( rowProcessingState );
initializer.resolveInstance( rowProcessingState );
}
return initializer.getInitializedInstance();
final Object initializedInstance = initializer.getInitializedInstance();
if ( initializedInstance instanceof HibernateProxy ) {
if ( initializedInstance.getClass()
.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass().getClass() ) ) {
return initializedInstance;
}
initializer.initializeInstance( rowProcessingState );
return ( (HibernateProxy) initializedInstance ).getHibernateLazyInitializer().getImplementation();
}
return initializedInstance;
}
private Object loadByUniqueKey(

View File

@ -6,9 +6,11 @@
*/
package org.hibernate.orm.test.polymorphic;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
@ -18,20 +20,26 @@
import static org.assertj.core.api.Assertions.assertThat;
public class PolymorphicAssociationTest extends BaseCoreFunctionalTestCase {
@DomainModel(
annotatedClasses = {
PolymorphicAssociationTest.Level1.class,
PolymorphicAssociationTest.Level2.class,
PolymorphicAssociationTest.DerivedLevel2.class,
PolymorphicAssociationTest.Level3.class
}
)
@SessionFactory
public class PolymorphicAssociationTest {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Level1.class, Level2.class, DerivedLevel2.class, Level3.class };
}
@Test
public void test() {
inTransaction( session -> {
@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction( session -> {
Level1 level1 = new Level1();
level1.setId( 1 );
DerivedLevel2 level2 = new DerivedLevel2();
level2.setId( 2 );
Level3 level3 = new Level3();
level3.setId( 3 );
@ -46,15 +54,19 @@ public void test() {
session.save( level2 );
session.save( level3 );
} );
}
inTransaction( session -> {
@Test
public void testLoad(SessionFactoryScope scope) {
scope.inTransaction( session -> {
Level3 level3 = session.load( Level3.class, 3 );
Level2 level2 = level3.getLevel2Parent();
assertThat( level2 ).isNotNull();
assertThat( level2.getLevel3Child() ).extracting( "id" ).isEqualTo( 3 );
final Level3 level3Child = level2.getLevel3Child();
assertThat( level3Child ).extracting( "id" ).isEqualTo( 3 );
} );
inTransaction( session -> {
scope.inTransaction( session -> {
Level1 level1 = session.load( Level1.class, 1 );
DerivedLevel2 level2 = level1.getLevel2Child();
assertThat( level2 ).isNotNull();