HHH-16812 StackOverflowError an embeddable's @Parent is a subclass in an inheritance tree

This commit is contained in:
Andrea Boriero 2023-07-13 16:46:42 +02:00 committed by Andrea Boriero
parent d69138f1b9
commit 147f01ac0b
3 changed files with 47 additions and 12 deletions

View File

@ -8,6 +8,8 @@ package org.hibernate;
import java.util.Collection;
import org.hibernate.proxy.HibernateProxy;
/**
* @author Steve Ebersole
*/
@ -47,7 +49,7 @@ public class PropertySetterAccessException extends PropertyAccessException {
}
public static String loggablePropertyValueString(Object value) {
if ( value instanceof Collection ) {
if ( value instanceof Collection || value instanceof HibernateProxy ) {
return value.getClass().getSimpleName();
}
return value.toString();

View File

@ -375,6 +375,17 @@ public final class ManagedTypeHelper {
throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to SelfDirtinessTracker" );
}
/**
* Cast the object to an HibernateProxy, or return null in case it is not an instance of HibernateProxy
* @param entity the entity to cast
* @return the same instance after casting or null if it is not an instance of HibernateProxy
*/
public static HibernateProxy asHibernateProxyOrNull(final Object entity) {
return entity instanceof PrimeAmongSecondarySupertypes ?
( (PrimeAmongSecondarySupertypes) entity ).asHibernateProxy() :
null;
}
private static final class TypeMeta {
final boolean isManagedType;
final boolean isSelfDirtinessTrackerType;

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.results.graph.embeddable;
import org.hibernate.engine.internal.ManagedTypeHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
@ -372,7 +373,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
return;
}
final Object parent = determineParentInstance( processingState );
Initializer parentInitializer = determineParentInitializer( processingState );
final Object parent = determineParentInstance( parentInitializer );
if ( parent == null ) {
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf(
"Unable to determine parent for injection into embeddable [%s]",
@ -388,10 +390,27 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
compositeInstance
);
parentInjectionAccess.getSetter().set( compositeInstance, parent );
final HibernateProxy proxy;
if ( fetchParentAccess != null
&& ( proxy = ManagedTypeHelper.asHibernateProxyOrNull( parent ) ) != null ) {
assert parentInitializer != null;
assert parentInitializer instanceof EntityInitializer;
parentInitializer.asEntityInitializer().registerResolutionListener(
o ->
parentInjectionAccess.getSetter()
.set(
compositeInstance,
proxy.getHibernateLazyInitializer().getImplementation()
)
);
}
else {
parentInjectionAccess.getSetter().set( compositeInstance, parent );
}
}
private Object determineParentInstance(RowProcessingState processingState) {
private Initializer determineParentInitializer(RowProcessingState processingState){
// use `fetchParentAccess` if it is available - it is more efficient
// and the correct way to do it.
@ -409,8 +428,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// todo (6.x) - allow injection of containing composite as parent if
// it is the direct parent
final FetchParentAccess firstEntityDescriptorAccess = fetchParentAccess.findFirstEntityDescriptorAccess();
return firstEntityDescriptorAccess.getInitializedInstance();
return fetchParentAccess.findFirstEntityDescriptorAccess();
}
// Otherwise, fallback to determining the parent-initializer by path
@ -418,11 +436,15 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// comment above
final NavigablePath parentPath = navigablePath.getParent();
if ( parentPath == null ) {
return null;
}
assert parentPath != null;
final Initializer parentInitializer = processingState.resolveInitializer( parentPath );
return processingState.resolveInitializer( parentPath );
}
private Object determineParentInstance(Initializer parentInitializer) {
if ( parentInitializer == null ) {
throw new UnsupportedOperationException( "Cannot determine Embeddable: " + navigablePath + " parent instance, parent initializer is null" );
}
if ( parentInitializer.isCollectionInitializer() ) {
return ( (CollectionInitializer) parentInitializer ).getCollectionInstance().getOwner();
@ -430,10 +452,10 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
final EntityInitializer parentEntityInitializer = parentInitializer.asEntityInitializer();
if ( parentEntityInitializer != null ) {
return parentEntityInitializer.getEntityInstance();
return parentEntityInitializer.getInitializedInstance();
}
throw new UnsupportedOperationException();
throw new UnsupportedOperationException( "The Embeddable: " + navigablePath + " parent initializer is neither an instance of an EntityInitializer nor of a CollectionInitializer" );
}
@Override