mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-08 10:49:37 +00:00
Fix issue with Hibernate proxy
This commit is contained in:
parent
d845f4b066
commit
f765eb4a87
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user