HHH-16282 Make it possible for Hibernate Reactive to plug in custom fetch initializers

This commit is contained in:
Davide D'Alto 2023-03-10 17:43:22 +01:00 committed by Sanne Grinovero
parent ff19a9124f
commit 06e24bd420
9 changed files with 250 additions and 70 deletions

View File

@ -157,6 +157,33 @@ public class ToOneAttributeMapping
private String identifyingColumnsTableExpression;
private boolean canUseParentTableGroup;
protected ToOneAttributeMapping(ToOneAttributeMapping delegate) {
super(
delegate.getAttributeName(),
delegate.getStateArrayPosition(),
delegate.getFetchableKey(),
delegate.getAttributeMetadata(),
delegate.getMappedFetchOptions(),
delegate.getDeclaringType(),
delegate.getPropertyAccess()
);
navigableRole = delegate.navigableRole;
isInternalLoadNullable = delegate.isInternalLoadNullable;
notFoundAction = delegate.notFoundAction;
unwrapProxy = delegate.unwrapProxy;
isOptional = delegate.isOptional;
entityMappingType = delegate.entityMappingType;
referencedPropertyName = delegate.referencedPropertyName;
targetKeyPropertyName = delegate.targetKeyPropertyName;
cardinality = delegate.cardinality;
bidirectionalAttributePath = delegate.bidirectionalAttributePath;
declaringTableGroupProducer = delegate.declaringTableGroupProducer;
isKeyTableNullable = delegate.isKeyTableNullable;
sqlAliasStem = delegate.sqlAliasStem;
targetKeyPropertyNames = delegate.targetKeyPropertyNames;
isNullable = delegate.isNullable;
foreignKeyDescriptor = delegate.foreignKeyDescriptor;
}
public ToOneAttributeMapping(
String name,

View File

@ -23,6 +23,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
@ -69,12 +70,20 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin.getJoinedGroup();
}
);
afterInitialize( this, creationState );
}
// For Hibernate Reactive
protected EmbeddableFetchImpl(EmbeddableFetchImpl original) {
super( original.getFetchContainer(), original.getNavigablePath() );
fetchParent = original.fetchParent;
fetchTiming = original.fetchTiming;
tableGroup = original.tableGroup;
hasTableGroup = original.hasTableGroup;
}
@Override
public FetchTiming getTiming() {
return fetchTiming;
@ -133,11 +142,7 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
final EmbeddableInitializer initializer = creationState.resolveInitializer(
getNavigablePath(),
getReferencedModePart(),
() -> new EmbeddableFetchInitializer(
parentAccess,
this,
creationState
)
() -> buildEmbeddableFetchInitializer( parentAccess, this, creationState )
).asEmbeddableInitializer();
assert initializer != null;
@ -145,6 +150,13 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
return new EmbeddableAssembler( initializer );
}
protected Initializer buildEmbeddableFetchInitializer(
FetchParentAccess parentAccess,
EmbeddableResultGraphNode embeddableFetch,
AssemblerCreationState creationState) {
return new EmbeddableFetchInitializer( parentAccess, this, creationState );
}
@Override
public boolean appliesTo(GraphImplementor graphImplementor) {
return getFetchParent().appliesTo( graphImplementor );

View File

@ -213,10 +213,18 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
return navigablePath;
}
protected DomainResultAssembler<?> getIdentifierAssembler() {
return identifierAssembler;
}
protected boolean isMissing() {
return missing;
}
protected void setMissing(boolean missing) {
this.missing = missing;
}
protected abstract boolean isEntityReturn();
@Override
@ -1138,6 +1146,10 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
return lockMode;
}
protected DomainResultAssembler<?>[][] getAssemblers() {
return assemblers;
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
final SharedSessionContractImplementor session = rowProcessingState.getSession();

View File

@ -68,6 +68,10 @@ public abstract class AbstractNonLazyEntityFetch extends AbstractFetchParent imp
FetchParentAccess parentAccess,
AssemblerCreationState creationState) {
final EntityInitializer entityInitializer = getEntityInitializer( parentAccess, creationState );
return buildEntityAssembler( entityInitializer );
}
protected EntityAssembler buildEntityAssembler(EntityInitializer entityInitializer) {
return new EntityAssembler( getFetchedMapping().getJavaType(), entityInitializer );
}

View File

@ -15,7 +15,6 @@ import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
/**
* @author Andrea Boriero
@ -58,7 +57,7 @@ public class EntityDelayedFetchImpl extends AbstractNonJoinedEntityFetch {
final Initializer entityInitializer = creationState.resolveInitializer(
navigablePath,
getEntityValuedModelPart(),
() -> new EntityDelayedFetchInitializer(
() -> buildEntityDelayedFetchInitializer(
parentAccess,
navigablePath,
(ToOneAttributeMapping) getEntityValuedModelPart(),
@ -67,6 +66,20 @@ public class EntityDelayedFetchImpl extends AbstractNonJoinedEntityFetch {
)
);
return buildEntityAssembler( entityInitializer );
}
protected EntityAssembler buildEntityAssembler(Initializer entityInitializer) {
return new EntityAssembler( getFetchedMapping().getJavaType(), entityInitializer.asEntityInitializer() );
}
protected Initializer buildEntityDelayedFetchInitializer(FetchParentAccess parentAccess, NavigablePath navigablePath, ToOneAttributeMapping entityValuedModelPart, boolean selectByUniqueKey, DomainResultAssembler<?> resultAssembler) {
return new EntityDelayedFetchInitializer(
parentAccess,
navigablePath,
entityValuedModelPart,
selectByUniqueKey,
resultAssembler
);
}
}

View File

@ -183,14 +183,14 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
}
}
private EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {
protected EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {
if ( parentAccess != null ) {
return parentAccess.findFirstEntityInitializer();
}
return null;
}
private static boolean isEnhancedForLazyLoading(EntityInitializer parentEntityIntialiazer) {
protected static boolean isEnhancedForLazyLoading(EntityInitializer parentEntityIntialiazer) {
return parentEntityIntialiazer != null && parentEntityIntialiazer.getEntityDescriptor()
.getBytecodeEnhancementMetadata()
.isEnhancedForLazyLoading();
@ -219,6 +219,10 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
return entityInstance;
}
protected void setEntityInstance(Object entityInstance) {
this.entityInstance = entityInstance;
}
@Override
public EntityKey getEntityKey() {
throw new UnsupportedOperationException();
@ -259,4 +263,19 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
return "EntityDelayedFetchInitializer(" + LoggingHelper.toLoggableString( navigablePath ) + ")";
}
protected Object getIdentifier() {
return identifier;
}
protected void setIdentifier(Object identifier) {
this.identifier = identifier;
}
protected boolean isSelectByUniqueKey() {
return selectByUniqueKey;
}
protected DomainResultAssembler<?> getIdentifierAssembler() {
return identifierAssembler;
}
}

View File

@ -17,7 +17,6 @@ import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -68,18 +67,33 @@ public class EntityDelayedResultImpl implements DomainResult {
final Initializer initializer = creationState.resolveInitializer(
getNavigablePath(),
entityValuedModelPart,
() -> new EntityDelayedFetchInitializer(
null,
() -> buildEntityDelayedFetchInitializer(
getNavigablePath(),
(ToOneAttributeMapping) entityValuedModelPart,
false,
identifierResult.createResultAssembler( parentAccess, creationState )
)
);
return buildEntityAssembler( initializer );
}
protected EntityAssembler buildEntityAssembler(Initializer initializer) {
return new EntityAssembler( getResultJavaType(), initializer.asEntityInitializer() );
}
protected Initializer buildEntityDelayedFetchInitializer(
NavigablePath navigablePath,
ToOneAttributeMapping entityValuedModelPart,
DomainResultAssembler resultAssembler) {
return new EntityDelayedFetchInitializer(
null,
navigablePath,
(ToOneAttributeMapping) entityValuedModelPart,
false,
resultAssembler
);
}
@Override
public String toString() {
return "EntityDelayedResultImpl {" + getNavigablePath() + "}";

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.entity.internal;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
@ -37,6 +38,14 @@ public class EntityFetchSelectImpl extends AbstractNonJoinedEntityFetch {
this.keyResult = keyResult;
this.selectByUniqueKey = selectByUniqueKey;
}
// For Hibernate Reactive
protected EntityFetchSelectImpl(EntityFetchSelectImpl original) {
super( original.getNavigablePath(), original.getFetchedMapping(), original.getFetchParent() );
this.keyResult = original.keyResult;
this.selectByUniqueKey = original.selectByUniqueKey;
}
@Override
@ -56,18 +65,40 @@ public class EntityFetchSelectImpl extends AbstractNonJoinedEntityFetch {
final Initializer initializer = creationState.resolveInitializer(
getNavigablePath(),
getFetchedMapping(),
() ->
EntitySelectFetchInitializerBuilder.createInitializer(
parentAccess,
(ToOneAttributeMapping) getFetchedMapping(),
getReferencedMappingContainer().getEntityPersister(),
keyResult,
getNavigablePath(),
selectByUniqueKey,
creationState
)
() -> buildEntitySelectFetchInitializer(
parentAccess,
(ToOneAttributeMapping) getFetchedMapping(),
getReferencedMappingContainer().getEntityPersister(),
keyResult,
getNavigablePath(),
selectByUniqueKey,
creationState
)
);
return buildEntityAssembler( initializer );
}
protected Initializer buildEntitySelectFetchInitializer(
FetchParentAccess parentAccess,
ToOneAttributeMapping fetchedMapping,
EntityPersister entityPersister,
DomainResult<?> keyResult,
NavigablePath navigablePath,
boolean selectByUniqueKey,
AssemblerCreationState creationState) {
return EntitySelectFetchInitializerBuilder.createInitializer(
parentAccess,
fetchedMapping,
entityPersister,
keyResult,
navigablePath,
selectByUniqueKey,
creationState
);
}
protected DomainResultAssembler<?> buildEntityAssembler(Initializer initializer) {
return new EntityAssembler( getResultJavaType(), initializer.asEntityInitializer() );
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.results.internal.domain;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.BiDirectionalFetch;
@ -59,7 +60,18 @@ public class CircularFetchImpl implements BiDirectionalFetch {
this.referencedNavigablePath = referencedNavigablePath;
this.fetchable = fetchable;
this.keyResult = keyResult;
}
protected CircularFetchImpl(CircularFetchImpl original) {
this.referencedModelPart = original.referencedModelPart;
this.entityMappingType = original.entityMappingType;
this.timing = original.timing;
this.fetchParent = original.fetchParent;
this.navigablePath = original.navigablePath;
this.selectByUniqueKey = original.selectByUniqueKey;
this.referencedNavigablePath = original.referencedNavigablePath;
this.fetchable = original.fetchable;
this.keyResult = original.keyResult;
}
@Override
@ -95,28 +107,7 @@ public class CircularFetchImpl implements BiDirectionalFetch {
final Initializer initializer = creationState.resolveInitializer(
getNavigablePath(),
referencedModelPart,
() -> {
if ( timing == FetchTiming.IMMEDIATE ) {
return EntitySelectFetchInitializerBuilder.createInitializer(
parentAccess,
fetchable,
entityMappingType.getEntityPersister(),
keyResult,
getNavigablePath(),
selectByUniqueKey,
creationState
);
}
else {
return new EntityDelayedFetchInitializer(
parentAccess,
getReferencedPath(),
fetchable,
selectByUniqueKey,
keyResult.createResultAssembler( parentAccess, creationState )
);
}
}
() -> initializerFactory( parentAccess, creationState )
);
return new BiDirectionalFetchAssembler(
@ -125,39 +116,96 @@ public class CircularFetchImpl implements BiDirectionalFetch {
);
}
@Override
public FetchTiming getTiming() {
return timing;
protected Initializer initializerFactory(FetchParentAccess parentAccess, AssemblerCreationState creationState) {
if ( timing == FetchTiming.IMMEDIATE ) {
return buildEntitySelectFetchInitializer(
parentAccess,
fetchable,
entityMappingType.getEntityPersister(),
keyResult,
getNavigablePath(),
selectByUniqueKey,
creationState
);
}
else {
return buildEntityDelayedFetchInitializer(
parentAccess,
getReferencedPath(),
fetchable,
selectByUniqueKey,
keyResult.createResultAssembler( parentAccess, creationState )
);
}
}
@Override
public boolean hasTableGroup() {
return true;
protected Initializer buildEntitySelectFetchInitializer(
FetchParentAccess parentAccess,
ToOneAttributeMapping fetchable,
EntityPersister entityPersister,
DomainResult<?> keyResult,
NavigablePath navigablePath,
boolean selectByUniqueKey,
AssemblerCreationState creationState) {
return EntitySelectFetchInitializerBuilder
.createInitializer(
parentAccess,
this.fetchable,
entityPersister,
keyResult,
navigablePath,
selectByUniqueKey,
creationState
);
}
private static class BiDirectionalFetchAssembler implements DomainResultAssembler {
private EntityInitializer initializer;
private JavaType assembledJavaType;
protected Initializer buildEntityDelayedFetchInitializer(
FetchParentAccess parentAccess,
NavigablePath referencedPath,
ToOneAttributeMapping fetchable,
boolean selectByUniqueKey,
DomainResultAssembler<?> resultAssembler) {
return new EntityDelayedFetchInitializer(
parentAccess,
referencedPath,
fetchable,
selectByUniqueKey,
resultAssembler
);
}
public BiDirectionalFetchAssembler(
EntityInitializer initializer,
JavaType assembledJavaType) {
this.initializer = initializer;
this.assembledJavaType = assembledJavaType;
@Override
public FetchTiming getTiming ( ) {
return timing;
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
initializer.resolveInstance( rowProcessingState );
return initializer.getInitializedInstance();
public boolean hasTableGroup ( ) {
return true;
}
@Override
public JavaType getAssembledJavaType() {
return assembledJavaType;
private static class BiDirectionalFetchAssembler implements DomainResultAssembler {
private EntityInitializer initializer;
private JavaType assembledJavaType;
public BiDirectionalFetchAssembler(
EntityInitializer initializer,
JavaType assembledJavaType) {
this.initializer = initializer;
this.assembledJavaType = assembledJavaType;
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
initializer.resolveInstance( rowProcessingState );
return initializer.getInitializedInstance();
}
@Override
public JavaType getAssembledJavaType() {
return assembledJavaType;
}
}
}
}