55 */
66package org .hibernate .reactive .sql .results .graph .embeddable .internal ;
77
8+
89import java .util .concurrent .CompletionStage ;
910import java .util .function .BiFunction ;
11+ import java .util .function .Supplier ;
1012
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 ;
2331import static org .hibernate .reactive .util .impl .CompletionStages .voidFuture ;
32+ import static org .hibernate .reactive .util .impl .CompletionStages .whileLoop ;
33+ import static org .hibernate .sql .results .graph .entity .internal .BatchEntityInsideEmbeddableSelectFetchInitializer .BATCH_PROPERTY ;
2434
2535public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
2636 implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
@@ -33,6 +43,14 @@ public ReactiveEmbeddableInitializerData(
3343 super ( initializer , rowProcessingState );
3444 }
3545
46+ public Object [] getRowState (){
47+ return rowState ;
48+ }
49+
50+ public EmbeddableMappingType .ConcreteEmbeddableType getEmbeddableType () {
51+ return concreteEmbeddableType ;
52+ }
53+
3654 @ Override
3755 public void setState (State state ) {
3856 super .setState ( state );
@@ -64,10 +82,140 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
6482
6583 @ Override
6684 public CompletionStage <Void > reactiveResolveInstance (EmbeddableInitializerData data ) {
67- super .resolveInstance ( data );
85+ if ( data .getState () != State .KEY_RESOLVED ) {
86+ return voidFuture ();
87+ }
88+
89+ data .setState ( State .RESOLVED );
90+ return extractRowState ( (ReactiveEmbeddableInitializerData ) data )
91+ .thenAccept ( unused -> prepareCompositeInstance ( (ReactiveEmbeddableInitializerData ) data ) );
92+ }
93+
94+ private CompletionStage <Void > extractRowState (ReactiveEmbeddableInitializerData data ) {
95+ final DomainResultAssembler <?>[] subAssemblers = assemblers [data .getSubclassId ()];
96+ final RowProcessingState rowProcessingState = data .getRowProcessingState ();
97+ final Object [] rowState = data .getRowState ();
98+ final boolean [] stateAllNull = {true };
99+ final int [] index = {0 };
100+ final WhileCondition whileCondition = new WhileCondition (subAssemblers , index );
101+ return whileLoop ( whileCondition , () -> {
102+ final int i = index [0 ];
103+ final DomainResultAssembler <?> assembler = subAssemblers [i ];
104+ final CompletionStage <Void > completionStage ;
105+ if ( assembler instanceof ReactiveDomainResultsAssembler <?> reactiveAssembler ) {
106+ completionStage = reactiveAssembler .reactiveAssemble ( (ReactiveRowProcessingState ) rowProcessingState )
107+ .thenCompose ( contributorValue -> setContributorValue (
108+ contributorValue ,
109+ i ,
110+ rowState ,
111+ stateAllNull ,
112+ whileCondition
113+ ) );
114+ }
115+ else {
116+ completionStage = setContributorValue (
117+ assembler == null ? null : assembler .assemble ( rowProcessingState ),
118+ i ,
119+ rowState ,
120+ stateAllNull ,
121+ whileCondition
122+ );
123+ }
124+ index [0 ] = i + 1 ;
125+ return completionStage ;
126+ })
127+ .whenComplete (
128+ (unused , throwable ) -> {
129+ if ( stateAllNull [0 ] ) {
130+ data .setState ( State .MISSING );
131+ }
132+ }
133+ );
134+ }
135+
136+ private static class WhileCondition implements Supplier <Boolean > {
137+ boolean forceExit ;
138+ final int maxIndex ;
139+ final int [] currentIndex ;
140+
141+ public WhileCondition (DomainResultAssembler <?>[] subAssemblers , int [] index ) {
142+ maxIndex = subAssemblers .length ;
143+ currentIndex = index ;
144+ }
145+
146+ @ Override
147+ public Boolean get () {
148+ return currentIndex [0 ] < maxIndex && !forceExit ;
149+ }
150+ }
151+
152+ private CompletionStage <Void > setContributorValue (
153+ Object contributorValue ,
154+ int index ,
155+ Object [] rowState ,
156+ boolean [] stateAllNull ,
157+ WhileCondition whileCondition ) {
158+ if ( contributorValue == BATCH_PROPERTY ) {
159+ rowState [index ] = null ;
160+ }
161+ else {
162+ rowState [index ] = contributorValue ;
163+ }
164+ if ( contributorValue != null ) {
165+ stateAllNull [0 ] = false ;
166+ }
167+ else if ( isPartOfKey () ) {
168+ // If this is a foreign key and there is a null part, the whole thing has to be turned into null
169+ stateAllNull [0 ] = true ;
170+ whileCondition .forceExit = true ;
171+ }
68172 return voidFuture ();
69173 }
70174
175+ private CompletionStage <Void > prepareCompositeInstance (ReactiveEmbeddableInitializerData data ) {
176+ // Virtual model parts use the owning entity as container which the fetch parent access provides.
177+ // For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
178+ // so we can't use the fetch parent access in that case.
179+ final ReactiveInitializer <ReactiveEmbeddableInitializerData > parent = (ReactiveInitializer <ReactiveEmbeddableInitializerData >) getParent ();
180+ if ( parent != null && getInitializedPart () instanceof VirtualModelPart && !isPartOfKey () && data .getState () != State .MISSING ) {
181+ final ReactiveEmbeddableInitializerData subData = parent .getData ( data .getRowProcessingState () );
182+ return parent .reactiveResolveInstance ( subData )
183+ .thenAccept (
184+ unused -> {
185+ data .setInstance ( parent .getResolvedInstance ( subData ) );
186+ if ( data .getState () != State .INITIALIZED && data .getInstance () == null ) {
187+ createCompositeInstance ( data )
188+ .thenAccept ( o -> data .setInstance ( o ) );
189+ }
190+ }
191+ ).thenAccept ( unused -> {
192+ if ( data .getInstance () == null ) {
193+ createCompositeInstance ( data )
194+ .thenAccept ( data ::setInstance );
195+ }
196+ } );
197+ }
198+
199+ if ( data .getInstance () == null ) {
200+ return createCompositeInstance ( data )
201+ .thenAccept ( data ::setInstance );
202+ }
203+ return voidFuture ();
204+ }
205+
206+ private CompletionStage <Object > createCompositeInstance (ReactiveEmbeddableInitializerData data ) {
207+ if ( data .getState () == State .MISSING ) {
208+ return completedFuture ( null );
209+ }
210+
211+ final EmbeddableInstantiator instantiator = data .getConcreteEmbeddableType () == null
212+ ? getInitializedPart ().getEmbeddableTypeDescriptor ().getRepresentationStrategy ().getInstantiator ()
213+ : data .getConcreteEmbeddableType ().getInstantiator ();
214+ final Object instance = instantiator .instantiate ( data );
215+ data .setState ( State .RESOLVED );
216+ return completedFuture ( instance );
217+ }
218+
71219 @ Override
72220 public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73221 super .initializeInstance ( data );
0 commit comments