HHH-16812 StackOverflowError an embeddable's @Parent is a subclass in an inheritance tree
This commit is contained in:
parent
d69138f1b9
commit
147f01ac0b
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue