Fix Stack Overflow caused by EntitySelectFetchByUniqueKeyInitializer
This commit is contained in:
parent
ecd9d2a193
commit
d6bdca77f2
|
@ -15,7 +15,7 @@ import org.hibernate.persister.entity.UniqueKeyLoadable;
|
|||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
|
||||
/**
|
||||
|
@ -66,16 +66,27 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
|
|||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
entityInstance = persistenceContext.getEntity( euk );
|
||||
if ( entityInstance == null ) {
|
||||
entityInstance = ( (UniqueKeyLoadable) concreteDescriptor ).loadByUniqueKey(
|
||||
uniqueKeyPropertyName,
|
||||
entityIdentifier,
|
||||
session
|
||||
);
|
||||
final EntitySelectFetchByUniqueKeyInitializer initializer = (EntitySelectFetchByUniqueKeyInitializer) persistenceContext.getLoadContexts()
|
||||
.findInitializer( euk );
|
||||
if ( initializer == null ) {
|
||||
final JdbcValuesSourceProcessingState jdbcValuesSourceProcessingState = rowProcessingState.getJdbcValuesSourceProcessingState();
|
||||
jdbcValuesSourceProcessingState.registerInitilaizer( euk, this );
|
||||
|
||||
// If the entity was not in the Persistence Context, but was found now,
|
||||
// add it to the Persistence Context
|
||||
if ( entityInstance != null ) {
|
||||
persistenceContext.addEntity( euk, entityInstance );
|
||||
entityInstance = ( (UniqueKeyLoadable) concreteDescriptor ).loadByUniqueKey(
|
||||
uniqueKeyPropertyName,
|
||||
entityIdentifier,
|
||||
session
|
||||
);
|
||||
|
||||
// If the entity was not in the Persistence Context, but was found now,
|
||||
// add it to the Persistence Context
|
||||
if ( entityInstance != null ) {
|
||||
persistenceContext.addEntity( euk, entityInstance );
|
||||
}
|
||||
notifyResolutionListeners(entityInstance);
|
||||
}
|
||||
else {
|
||||
registerResolutionListener( instance -> entityInstance = instance );
|
||||
}
|
||||
}
|
||||
if ( entityInstance != null ) {
|
||||
|
@ -83,4 +94,5 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
|
|||
}
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,12 +14,14 @@ import java.util.function.BiConsumer;
|
|||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.service.spi.EventListenerGroup;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PostLoadEventListener;
|
||||
import org.hibernate.event.spi.PreLoadEvent;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
|
@ -47,6 +49,7 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
|
||||
private Map<EntityKey, LoadingEntityEntry> loadingEntityMap;
|
||||
private Map<EntityKey, Initializer> initializerMap;
|
||||
private Map<EntityUniqueKey, Initializer> initializerByUniquKeyMap;
|
||||
private Map<CollectionKey, LoadingCollectionEntry> loadingCollectionMap;
|
||||
private List<CollectionInitializer> arrayInitializers;
|
||||
|
||||
|
@ -122,6 +125,19 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInitilaizer(EntityUniqueKey entityKey, Initializer initializer) {
|
||||
if ( initializerByUniquKeyMap == null ) {
|
||||
initializerByUniquKeyMap = new HashMap<>();
|
||||
}
|
||||
initializerByUniquKeyMap.put( entityKey, initializer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Initializer findInitializer(EntityUniqueKey entityKey) {
|
||||
return initializerByUniquKeyMap == null ? null : initializerByUniquKeyMap.get( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Initializer findInitializer(EntityKey entityKey) {
|
||||
return initializerMap == null ? null : initializerMap.get( entityKey );
|
||||
|
|
|
@ -8,9 +8,11 @@ package org.hibernate.sql.results.jdbc.spi;
|
|||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PreLoadEvent;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.spi.LoadContexts;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
|
@ -60,8 +62,14 @@ public interface JdbcValuesSourceProcessingState {
|
|||
EntityKey entityKey,
|
||||
Initializer initializer);
|
||||
|
||||
void registerInitilaizer(
|
||||
EntityUniqueKey entityKey,
|
||||
Initializer initializer);
|
||||
|
||||
Initializer findInitializer(EntityKey entityKey);
|
||||
|
||||
Initializer findInitializer(EntityUniqueKey entityKey);
|
||||
|
||||
|
||||
/**
|
||||
* Find a LoadingCollectionEntry locally to this context.
|
||||
|
|
|
@ -8,11 +8,13 @@ package org.hibernate.sql.results.spi;
|
|||
|
||||
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.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.collections.StandardStack;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
|
@ -58,6 +60,18 @@ public class LoadContexts {
|
|||
);
|
||||
}
|
||||
|
||||
public Initializer findInitializer(EntityKey key){
|
||||
return jdbcValuesSourceProcessingStateStack.findCurrentFirst(
|
||||
state -> state.findInitializer( key )
|
||||
);
|
||||
}
|
||||
|
||||
public Initializer findInitializer(EntityUniqueKey key){
|
||||
return jdbcValuesSourceProcessingStateStack.findCurrentFirst(
|
||||
state -> state.findInitializer( key )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the persistence context to which this is bound.
|
||||
*
|
||||
|
|
|
@ -49,14 +49,20 @@ public class OneToOneOwnerByContainedEagerCyclesTest extends BaseCoreFunctionalT
|
|||
containing2.setChild( containing3 );
|
||||
containing3.setParent( containing2 );
|
||||
|
||||
Containing containing4 = new Containing();
|
||||
containing4.setId( 4 );
|
||||
|
||||
containing3.setChild( containing4 );
|
||||
containing4.setParent( containing3 );
|
||||
|
||||
Contained contained1 = new Contained();
|
||||
contained1.setId( 4 );
|
||||
contained1.setId( 5 );
|
||||
contained1.setText( "initialValue" );
|
||||
containing2.setContained( contained1 );
|
||||
contained1.setContaining( containing2 );
|
||||
|
||||
Contained contained2 = new Contained();
|
||||
contained2.setId( 5 );
|
||||
contained2.setId( 6 );
|
||||
contained2.setText( "initialOutOfScopeValue" );
|
||||
containing3.setContained( contained2 );
|
||||
contained2.setContaining( containing3 );
|
||||
|
@ -64,14 +70,21 @@ public class OneToOneOwnerByContainedEagerCyclesTest extends BaseCoreFunctionalT
|
|||
session.persist( contained1 );
|
||||
session.persist( contained2 );
|
||||
session.persist( containing3 );
|
||||
session.persist( containing4 );
|
||||
session.persist( containing2 );
|
||||
session.persist( containing1 );
|
||||
} );
|
||||
|
||||
// Test updating the value
|
||||
inTransaction( session -> {
|
||||
Contained contained = session.get( Contained.class, 4 );
|
||||
Contained contained = session.get( Contained.class, 5 );
|
||||
assertThat( contained ).isNotNull();
|
||||
final Containing containing2 = contained.containing;
|
||||
assertThat( containing2 ).isNotNull();
|
||||
final Containing containing3 = containing2.child;
|
||||
assertThat( containing3 ).isNotNull();
|
||||
assertThat( containing3.parent ).isEqualTo( containing2 );
|
||||
assertThat( containing3.child ).isNotNull();
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue