From ba0fa8c26d154abcf77a2dcd0f581504335bf588 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 1 Feb 2023 16:13:32 +0100 Subject: [PATCH] HHH-15969 Inheritance: org.hibernate.PropertyAccessException Exception --- .../entity/AbstractEntityInitializer.java | 62 ++++++++++++++++++- ...luesSourceProcessingStateStandardImpl.java | 1 - 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index da10d01e80..f02885a208 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -26,7 +26,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.Status; -import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.spi.PreLoadEvent; import org.hibernate.event.spi.PreLoadEventListener; import org.hibernate.internal.util.StringHelper; @@ -51,6 +50,7 @@ import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.basic.BasicResultAssembler; import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer; import org.hibernate.sql.results.internal.NullValueAssembler; @@ -379,6 +379,10 @@ private boolean useEmbeddedIdentifierInstanceAsEntity(Object id) { @Override public void resolveInstance(RowProcessingState rowProcessingState) { if ( !missing && !isInitialized ) { + if ( shouldSkipResolveInstance( rowProcessingState ) ) { + missing = true; + return; + } // Special case map proxy to avoid stack overflows // We know that a map proxy will always be of "the right type" so just use that object final LoadingEntityEntry existingLoadingEntry = @@ -395,6 +399,62 @@ else if ( existingLoadingEntry != null && existingLoadingEntry.getEntityInitiali } } + private boolean shouldSkipResolveInstance(RowProcessingState rowProcessingState) { + final NavigablePath parent = navigablePath.getParent(); + if ( parent != null ) { + final Initializer parentInitializer = rowProcessingState.resolveInitializer( parent ); + if ( parentInitializer != null && parentInitializer.isEntityInitializer() ) { + if ( isReferencedModelPartAssignableToConcreteParent( parentInitializer ) ) { + return true; + } + } + } + return false; + } + + private boolean isReferencedModelPartAssignableToConcreteParent(Initializer parentInitializer) { + final EntityPersister parentConcreteDescriptor = parentInitializer.asEntityInitializer() + .getConcreteDescriptor(); + if ( parentConcreteDescriptor != null && parentConcreteDescriptor.getEntityMetamodel().isPolymorphic()) { + final ModelPart concreteModelPart = parentConcreteDescriptor.findByPath( navigablePath.getLocalName() ); + if ( concreteModelPart == null + || !referencedModelPart.getJavaType().getJavaTypeClass() + .isAssignableFrom( concreteModelPart.getJavaType().getJavaTypeClass() ) ) { + /* + Given: + + class Message{ + + @ManyToOne + Address address; + } + + @Inheritance(strategy = InheritanceType.SINGLE_TABLE) + class Address{ + } + + class AddressA extends Address { + @OneToOne(mappedBy = "addressA") + UserA userA; + } + + class AddressB extends Address{ + @OneToOne(mappedBy = "addressB") + UserB userB; + } + + when we try to initialize the messages of Message.address, + there will be one EntityJoinedFetchInitializer for UserA and one for UserB so + when resolving AddressA we have to skip resolving the EntityJoinedFetchInitializer of UserB + and for AddressB skip resolving the EntityJoinedFetchInitializer of UserA + + */ + return true; + } + } + return false; + } + private void resolveEntityInstance( RowProcessingState rowProcessingState, LoadingEntityEntry existingLoadingEntry, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java index 61e3ac1e66..69596497d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java @@ -15,7 +15,6 @@ import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityUniqueKey; -import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.spi.EventSource;