From a9fce4b69dd2698268817c23a0dd2898ef410bdc Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 30 Nov 2021 19:34:37 -0600 Subject: [PATCH] Introduce `VirtualIdEmbeddable` and `IdClassEmbeddable` + instantiators EmbeddableInitializer fully uses EmbeddableInstantiator and value injection Still need to - integrate EmbeddableInstantiator work (ComponentType/ComponentTuplizer) - integrate embedded forms. `VirtualIdEmbeddable` does not really need it as it can use the id-mapping itself as the embedded form. But `IdClassEmbedded` should really be integrated - integrate `VirtualKeyEmbeddable` and `VirtualKeyEmbedded` for use as inverse composite fks - share `#finishInit` handling for `EmbeddableMappingType`, `VirtualIdEmbeddable` and `IdClassEmbeddable` - ability to use the containing composite owner as the parent of a composite (legacy behavior is to always use the "first" entity --- .../AbstractEmbeddableInitializer.java | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index 785ac3c687..00b73b01c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -67,6 +67,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA // and every row private final Object[] resolvedValues; private Boolean allValuesNull; + private Boolean stateInjected; private Object compositeInstance; @@ -155,6 +156,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA navigablePath ); + stateInjected = false; + extractRowState( processingState ); prepareCompositeInstance( processingState ); handleParentInjection( processingState ); @@ -165,9 +168,10 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA if ( compositeInstance instanceof HibernateProxy ) { final Initializer parentInitializer = processingState.resolveInitializer( navigablePath.getParent() ); if ( parentInitializer != this ) { - ( (FetchParentAccess) parentInitializer ).registerResolutionListener( - (entity) -> representationEmbeddable.setPropertyValues( entity, resolvedValues ) - ); + ( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> { + representationEmbeddable.setPropertyValues( entity, resolvedValues ); + stateInjected = true; + } ); } else { // At this point, createEmptyCompositesEnabled is always true, so we generate @@ -182,13 +186,15 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA final Object target = representationStrategy .getInstantiator() .instantiate( valuesAccess, sessionFactory); + stateInjected = true; ( (HibernateProxy) compositeInstance ).getHibernateLazyInitializer().setImplementation( target ); } } - else if ( allValuesNull == FALSE ) { + else if ( allValuesNull == FALSE && stateInjected != TRUE ) { // todo (6.0) : i think this is still called for cases where // we have already done the "ctor injection" representationEmbeddable.setPropertyValues( compositeInstance, resolvedValues ); + stateInjected = true; } } } @@ -290,8 +296,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA final Supplier valuesAccess = allValuesNull == TRUE ? null : () -> resolvedValues; - final Object instance = representationStrategy.getInstantiator().instantiate( valuesAccess, sessionFactory ); + stateInjected = true; EmbeddableLoadingLogger.INSTANCE.debugf( "Created composite instance [%s] : %s", navigablePath, instance ); @@ -299,12 +305,6 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA } private void handleParentInjection(RowProcessingState processingState) { - final PropertyAccess parentInjectionAccess = embedded.getParentInjectionAttributePropertyAccess(); - if ( parentInjectionAccess == null ) { - // embeddable defined no parent injection - return; - } - // todo (6.0) : should we initialize the composite instance if we get here and it is null (not NULL_MARKER)? // we want to avoid injection for `NULL_MARKER` @@ -316,6 +316,12 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA return; } + final PropertyAccess parentInjectionAccess = embedded.getParentInjectionAttributePropertyAccess(); + if ( parentInjectionAccess == null ) { + // embeddable defined no parent injection + return; + } + final Object parent = determineParentInstance( processingState ); if ( parent == null ) { EmbeddableLoadingLogger.INSTANCE.debugf( @@ -332,11 +338,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA compositeInstance ); - parentInjectionAccess.getSetter().set( - compositeInstance, - parent, - sessionFactory - ); + parentInjectionAccess.getSetter().set( compositeInstance, parent, sessionFactory ); } private Object determineParentInstance(RowProcessingState processingState) { @@ -387,6 +389,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA public void finishUpRow(RowProcessingState rowProcessingState) { compositeInstance = null; allValuesNull = null; + stateInjected = null; + clearResolutionListeners(); }