55 */
66package org .hibernate .reactive .sql .results .graph .embeddable .internal ;
77
8+
89import java .util .concurrent .CompletionStage ;
910import java .util .function .BiFunction ;
1011
12+ import org .hibernate .engine .spi .SessionFactoryImplementor ;
1113import org .hibernate .metamodel .mapping .EmbeddableMappingType ;
14+ import org .hibernate .metamodel .mapping .VirtualModelPart ;
15+ import org .hibernate .metamodel .spi .EmbeddableInstantiator ;
16+ import org .hibernate .reactive .sql .exec .spi .ReactiveRowProcessingState ;
17+ import org .hibernate .reactive .sql .results .graph .ReactiveDomainResultsAssembler ;
1218import org .hibernate .reactive .sql .results .graph .ReactiveInitializer ;
1319import org .hibernate .sql .results .graph .AssemblerCreationState ;
20+ import org .hibernate .sql .results .graph .DomainResultAssembler ;
1421import org .hibernate .sql .results .graph .Initializer ;
1522import org .hibernate .sql .results .graph .InitializerData ;
1623import org .hibernate .sql .results .graph .InitializerParent ;
1926import org .hibernate .sql .results .graph .embeddable .internal .EmbeddableInitializerImpl ;
2027import org .hibernate .sql .results .jdbc .spi .RowProcessingState ;
2128
29+ import static org .hibernate .reactive .util .impl .CompletionStages .completedFuture ;
2230import static org .hibernate .reactive .util .impl .CompletionStages .loop ;
31+ import static org .hibernate .reactive .util .impl .CompletionStages .nullFuture ;
2332import static org .hibernate .reactive .util .impl .CompletionStages .voidFuture ;
33+ import static org .hibernate .reactive .util .impl .CompletionStages .whileLoop ;
34+ import static org .hibernate .sql .results .graph .embeddable .EmbeddableLoadingLogger .EMBEDDED_LOAD_LOGGER ;
35+ import static org .hibernate .sql .results .graph .entity .internal .BatchEntityInsideEmbeddableSelectFetchInitializer .BATCH_PROPERTY ;
2436
2537public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
2638 implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
2739
40+ private final SessionFactoryImplementor sessionFactory ;
41+
2842 private static class ReactiveEmbeddableInitializerData extends EmbeddableInitializerData {
2943
3044 public ReactiveEmbeddableInitializerData (
@@ -33,6 +47,10 @@ public ReactiveEmbeddableInitializerData(
3347 super ( initializer , rowProcessingState );
3448 }
3549
50+ public Object [] getRowState (){
51+ return rowState ;
52+ }
53+
3654 @ Override
3755 public void setState (State state ) {
3856 super .setState ( state );
@@ -55,6 +73,7 @@ public ReactiveEmbeddableInitializerImpl(
5573 AssemblerCreationState creationState ,
5674 boolean isResultInitializer ) {
5775 super ( resultDescriptor , discriminatorFetch , parent , creationState , isResultInitializer );
76+ sessionFactory = creationState .getSqlAstCreationContext ().getSessionFactory ();
5877 }
5978
6079 @ Override
@@ -64,10 +83,129 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
6483
6584 @ Override
6685 public CompletionStage <Void > reactiveResolveInstance (EmbeddableInitializerData data ) {
67- super .resolveInstance ( data );
86+ if ( data .getState () != State .KEY_RESOLVED ) {
87+ return voidFuture ();
88+ }
89+
90+ data .setState ( State .RESOLVED );
91+ return extractRowState ( (ReactiveEmbeddableInitializerData ) data )
92+ .thenAccept ( unused -> prepareCompositeInstance ( (ReactiveEmbeddableInitializerData ) data ) );
93+ }
94+
95+ private CompletionStage <Void > extractRowState (ReactiveEmbeddableInitializerData data ) {
96+ final DomainResultAssembler <?>[] subAssemblers = assemblers [data .getSubclassId ()];
97+ final RowProcessingState rowProcessingState = data .getRowProcessingState ();
98+ final Object [] rowState = data .getRowState ();
99+ final boolean [] stateAllNull = {true };
100+ final int [] index = {0 };
101+ final boolean [] forceExit = { false };
102+ return whileLoop (
103+ () -> index [0 ] < subAssemblers .length && !forceExit [0 ],
104+ () -> {
105+ final int i = index [0 ]++;
106+ final DomainResultAssembler <?> assembler = subAssemblers [i ];
107+ if ( assembler instanceof ReactiveDomainResultsAssembler <?> ) {
108+ return ( (ReactiveDomainResultsAssembler <?>) assembler )
109+ .reactiveAssemble ( (ReactiveRowProcessingState ) rowProcessingState )
110+ .thenAccept ( contributorValue -> setContributorValue (
111+ contributorValue ,
112+ i ,
113+ rowState ,
114+ stateAllNull ,
115+ forceExit
116+ ) );
117+ }
118+ else {
119+ setContributorValue (
120+ assembler == null ? null : assembler .assemble ( rowProcessingState ),
121+ i ,
122+ rowState ,
123+ stateAllNull ,
124+ forceExit
125+ );
126+ return voidFuture ();
127+ }
128+ })
129+ .whenComplete (
130+ (unused , throwable ) -> {
131+ if ( stateAllNull [0 ] ) {
132+ data .setState ( State .MISSING );
133+ }
134+ }
135+ );
136+ }
137+
138+ private void setContributorValue (
139+ Object contributorValue ,
140+ int index ,
141+ Object [] rowState ,
142+ boolean [] stateAllNull ,
143+ boolean [] forceExit ) {
144+ if ( contributorValue == BATCH_PROPERTY ) {
145+ rowState [index ] = null ;
146+ }
147+ else {
148+ rowState [index ] = contributorValue ;
149+ }
150+ if ( contributorValue != null ) {
151+ stateAllNull [0 ] = false ;
152+ }
153+ else if ( isPartOfKey () ) {
154+ // If this is a foreign key and there is a null part, the whole thing has to be turned into null
155+ stateAllNull [0 ] = true ;
156+ forceExit [0 ] = true ;
157+ }
158+ }
159+
160+ private CompletionStage <Void > prepareCompositeInstance (ReactiveEmbeddableInitializerData data ) {
161+ // Virtual model parts use the owning entity as container which the fetch parent access provides.
162+ // For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
163+ // so we can't use the fetch parent access in that case.
164+ final ReactiveInitializer <ReactiveEmbeddableInitializerData > parent = (ReactiveInitializer <ReactiveEmbeddableInitializerData >) getParent ();
165+ if ( parent != null && getInitializedPart () instanceof VirtualModelPart && !isPartOfKey () && data .getState () != State .MISSING ) {
166+ final ReactiveEmbeddableInitializerData subData = parent .getData ( data .getRowProcessingState () );
167+ return parent
168+ .reactiveResolveInstance ( subData )
169+ .thenCompose (
170+ unused -> {
171+ data .setInstance ( parent .getResolvedInstance ( subData ) );
172+ if ( data .getState () == State .INITIALIZED ) {
173+ return voidFuture ();
174+ }
175+ return doCreateCompositeInstance ( data )
176+ .thenAccept ( v -> EMBEDDED_LOAD_LOGGER .debugf (
177+ "Created composite instance [%s]" ,
178+ getNavigablePath ()
179+ ) );
180+ } );
181+ }
182+
183+ return doCreateCompositeInstance ( data )
184+ .thenAccept ( v -> EMBEDDED_LOAD_LOGGER .debugf ( "Created composite instance [%s]" , getNavigablePath () ) );
185+
186+ }
187+
188+ private CompletionStage <Void > doCreateCompositeInstance (ReactiveEmbeddableInitializerData data ) {
189+ if ( data .getInstance () == null ) {
190+ return createCompositeInstance ( data )
191+ .thenAccept ( data ::setInstance );
192+ }
68193 return voidFuture ();
69194 }
70195
196+ private CompletionStage <Object > createCompositeInstance (ReactiveEmbeddableInitializerData data ) {
197+ if ( data .getState () == State .MISSING ) {
198+ return nullFuture ();
199+ }
200+
201+ final EmbeddableInstantiator instantiator = data .getConcreteEmbeddableType () == null
202+ ? getInitializedPart ().getEmbeddableTypeDescriptor ().getRepresentationStrategy ().getInstantiator ()
203+ : data .getConcreteEmbeddableType ().getInstantiator ();
204+ final Object instance = instantiator .instantiate ( data , sessionFactory );
205+ data .setState ( State .RESOLVED );
206+ return completedFuture ( instance );
207+ }
208+
71209 @ Override
72210 public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73211 super .initializeInstance ( data );
0 commit comments