HHH-16890 StackOverflowError when loading entities with @Proxy(lazy = false)
This commit is contained in:
parent
abaaa09225
commit
75d834efe9
|
@ -351,16 +351,6 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
else {
|
else {
|
||||||
// 2) build the EntityKey
|
// 2) build the EntityKey
|
||||||
entityKey = new EntityKey( id, concreteDescriptor );
|
entityKey = new EntityKey( id, concreteDescriptor );
|
||||||
// 3) schedule the EntityKey for batch loading, if possible
|
|
||||||
|
|
||||||
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
|
||||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( concreteDescriptor ) ) {
|
|
||||||
final PersistenceContext persistenceContext =
|
|
||||||
session.getPersistenceContextInternal();
|
|
||||||
if ( !persistenceContext.containsEntity( entityKey ) ) {
|
|
||||||
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,11 @@ package org.hibernate.sql.results.graph.entity.internal;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
@ -19,8 +23,11 @@ import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptableOrNull;
|
||||||
|
|
||||||
public abstract class AbstractBatchEntitySelectFetchInitializer extends AbstractFetchParentAccess
|
public abstract class AbstractBatchEntitySelectFetchInitializer extends AbstractFetchParentAccess
|
||||||
implements EntityInitializer {
|
implements EntityInitializer {
|
||||||
|
|
||||||
|
@ -32,7 +39,7 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
||||||
protected final ToOneAttributeMapping referencedModelPart;
|
protected final ToOneAttributeMapping referencedModelPart;
|
||||||
protected final EntityInitializer firstEntityInitializer;
|
protected final EntityInitializer firstEntityInitializer;
|
||||||
|
|
||||||
protected Object entityInstance;
|
protected Object initializedEntityInstance;
|
||||||
protected EntityKey entityKey;
|
protected EntityKey entityKey;
|
||||||
|
|
||||||
protected State state = State.UNINITIALIZED;
|
protected State state = State.UNINITIALIZED;
|
||||||
|
@ -90,18 +97,54 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
|
entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
|
||||||
|
|
||||||
state = State.KEY_RESOLVED;
|
state = State.KEY_RESOLVED;
|
||||||
|
|
||||||
rowProcessingState.getSession().getPersistenceContext()
|
|
||||||
.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
|
|
||||||
registerResolutionListener();
|
registerResolutionListener();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Object getExistingInitializedInstance(RowProcessingState rowProcessingState) {
|
||||||
|
assert entityKey != null;
|
||||||
|
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
||||||
|
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||||
|
final Object instance = persistenceContext.getEntity( entityKey );
|
||||||
|
if ( instance == null ) {
|
||||||
|
final LoadingEntityEntry loadingEntityEntry = persistenceContext
|
||||||
|
.getLoadContexts().findLoadingEntityEntry( entityKey );
|
||||||
|
if ( loadingEntityEntry != null ) {
|
||||||
|
return loadingEntityEntry.getEntityInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( isInitialized( instance ) ) {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInitialized(Object entity) {
|
||||||
|
final PersistentAttributeInterceptable attributeInterceptable = asPersistentAttributeInterceptableOrNull(
|
||||||
|
entity );
|
||||||
|
if ( attributeInterceptable == null ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final PersistentAttributeInterceptor interceptor =
|
||||||
|
attributeInterceptable.$$_hibernate_getInterceptor();
|
||||||
|
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||||
|
return ( (EnhancementAsProxyLazinessInterceptor) interceptor ).isInitialized();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerToBatchFetchQueue(RowProcessingState rowProcessingState) {
|
||||||
|
assert entityKey != null;
|
||||||
|
rowProcessingState.getSession().getPersistenceContext()
|
||||||
|
.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishUpRow(RowProcessingState rowProcessingState) {
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
entityInstance = null;
|
initializedEntityInstance = null;
|
||||||
entityKey = null;
|
entityKey = null;
|
||||||
state = State.UNINITIALIZED;
|
state = State.UNINITIALIZED;
|
||||||
clearResolutionListeners();
|
clearResolutionListeners();
|
||||||
|
@ -114,7 +157,7 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getEntityInstance() {
|
public Object getEntityInstance() {
|
||||||
return entityInstance;
|
return initializedEntityInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -129,8 +172,8 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerResolutionListener(Consumer<Object> listener) {
|
public void registerResolutionListener(Consumer<Object> listener) {
|
||||||
if ( entityInstance != null ) {
|
if ( initializedEntityInstance != null ) {
|
||||||
listener.accept( entityInstance );
|
listener.accept( initializedEntityInstance );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
super.registerResolutionListener( listener );
|
super.registerResolutionListener( listener );
|
||||||
|
|
|
@ -63,12 +63,23 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveInstance(RowProcessingState rowProcessingState) {
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
|
if ( state == State.INITIALIZED ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
||||||
if ( entityKey == null ) {
|
if ( entityKey == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
state = State.INITIALIZED;
|
||||||
|
initializedEntityInstance = getExistingInitializedInstance( rowProcessingState );
|
||||||
|
if ( initializedEntityInstance == null ) {
|
||||||
|
|
||||||
entityInstance = BATCH_PROPERTY;
|
// need to add the key to the batch queue only when the entity has not been already loaded or
|
||||||
|
// there isn't another initializer that is loading it
|
||||||
|
registerToBatchFetchQueue( rowProcessingState );
|
||||||
|
|
||||||
|
initializedEntityInstance = BATCH_PROPERTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -39,7 +39,21 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveInstance(RowProcessingState rowProcessingState) {
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
|
if ( state == State.INITIALIZED ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
||||||
|
if ( entityKey == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = State.INITIALIZED;
|
||||||
|
|
||||||
|
initializedEntityInstance = getExistingInitializedInstance( rowProcessingState );
|
||||||
|
if ( initializedEntityInstance == null ) {
|
||||||
|
// need to add the key to the batch queue only when the entity has not been already loaded or
|
||||||
|
// there isn't another initializer that is loading it
|
||||||
|
registerToBatchFetchQueue( rowProcessingState );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,32 +45,29 @@ public class BatchInitializeEntitySelectFetchInitializer extends AbstractBatchEn
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveInstance(RowProcessingState rowProcessingState) {
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
if ( state == State.INITIALIZED ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolveKey( rowProcessingState, referencedModelPart, parentAccess );
|
||||||
|
|
||||||
if ( entityKey == null ) {
|
if ( entityKey == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = State.INITIALIZED;
|
state = State.INITIALIZED;
|
||||||
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
initializedEntityInstance = getExistingInitializedInstance( rowProcessingState );
|
||||||
entityInstance = session.getPersistenceContext().getEntity( entityKey );
|
if ( initializedEntityInstance == null ) {
|
||||||
if ( entityInstance == null ) {
|
// need to add the key to the batch queue only when the entity has not been already loaded or
|
||||||
final LoadingEntityEntry loadingEntityEntry = rowProcessingState.getJdbcValuesSourceProcessingState()
|
// there isn't another initializer that is loading it
|
||||||
.findLoadingEntityLocally( entityKey );
|
registerToBatchFetchQueue( rowProcessingState );
|
||||||
if ( loadingEntityEntry != null ) {
|
// Force creating a proxy
|
||||||
loadingEntityEntry.getEntityInitializer().resolveInstance( rowProcessingState );
|
initializedEntityInstance = rowProcessingState.getSession().internalLoad(
|
||||||
entityInstance = loadingEntityEntry.getEntityInstance();
|
entityKey.getEntityName(),
|
||||||
}
|
entityKey.getIdentifier(),
|
||||||
else {
|
false,
|
||||||
// Force creating a proxy
|
false
|
||||||
entityInstance = session.internalLoad(
|
);
|
||||||
entityKey.getEntityName(),
|
toBatchLoad.add( entityKey );
|
||||||
entityKey.getIdentifier(),
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
toBatchLoad.add( entityKey );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.results.graph.Initializer;
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
import org.hibernate.sql.results.graph.collection.internal.AbstractCollectionInitializer;
|
import org.hibernate.sql.results.graph.collection.internal.AbstractCollectionInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.internal.AbstractBatchEntitySelectFetchInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
|
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
|
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
@ -118,7 +119,8 @@ public final class InitializersList {
|
||||||
private static boolean initializeFirst(final Initializer initializer) {
|
private static boolean initializeFirst(final Initializer initializer) {
|
||||||
return !( initializer instanceof EntityDelayedFetchInitializer )
|
return !( initializer instanceof EntityDelayedFetchInitializer )
|
||||||
&& !( initializer instanceof EntitySelectFetchInitializer )
|
&& !( initializer instanceof EntitySelectFetchInitializer )
|
||||||
&& !( initializer instanceof AbstractCollectionInitializer );
|
&& !( initializer instanceof AbstractCollectionInitializer )
|
||||||
|
&& !(initializer instanceof AbstractBatchEntitySelectFetchInitializer );
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializersList build(final Map<NavigablePath, Initializer> initializerMap) {
|
InitializersList build(final Map<NavigablePath, Initializer> initializerMap) {
|
||||||
|
|
Loading…
Reference in New Issue