55 */
66package org .hibernate .reactive .sql .results .graph .embeddable .internal ;
77
8+
89import java .util .concurrent .CompletionStage ;
910import java .util .function .BiFunction ;
1011
1112import org .hibernate .metamodel .mapping .EmbeddableMappingType ;
13+ import org .hibernate .metamodel .mapping .VirtualModelPart ;
14+ import org .hibernate .metamodel .spi .EmbeddableInstantiator ;
15+ import org .hibernate .reactive .sql .exec .spi .ReactiveRowProcessingState ;
16+ import org .hibernate .reactive .sql .results .graph .ReactiveDomainResultsAssembler ;
1217import org .hibernate .reactive .sql .results .graph .ReactiveInitializer ;
1318import org .hibernate .sql .results .graph .AssemblerCreationState ;
19+ import org .hibernate .sql .results .graph .DomainResultAssembler ;
1420import org .hibernate .sql .results .graph .Initializer ;
1521import org .hibernate .sql .results .graph .InitializerData ;
1622import org .hibernate .sql .results .graph .InitializerParent ;
1925import org .hibernate .sql .results .graph .embeddable .internal .EmbeddableInitializerImpl ;
2026import org .hibernate .sql .results .jdbc .spi .RowProcessingState ;
2127
28+ import static org .hibernate .reactive .util .impl .CompletionStages .completedFuture ;
2229import static org .hibernate .reactive .util .impl .CompletionStages .loop ;
30+ import static org .hibernate .reactive .util .impl .CompletionStages .nullFuture ;
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 .embeddable .EmbeddableLoadingLogger .EMBEDDED_LOAD_LOGGER ;
34+ import static org .hibernate .sql .results .graph .entity .internal .BatchEntityInsideEmbeddableSelectFetchInitializer .BATCH_PROPERTY ;
2435
2536public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
2637 implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
@@ -33,6 +44,10 @@ public ReactiveEmbeddableInitializerData(
3344 super ( initializer , rowProcessingState );
3445 }
3546
47+ public Object [] getRowState (){
48+ return rowState ;
49+ }
50+
3651 @ Override
3752 public void setState (State state ) {
3853 super .setState ( state );
@@ -64,10 +79,128 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
6479
6580 @ Override
6681 public CompletionStage <Void > reactiveResolveInstance (EmbeddableInitializerData data ) {
67- super .resolveInstance ( data );
82+ if ( data .getState () != State .KEY_RESOLVED ) {
83+ return voidFuture ();
84+ }
85+
86+ data .setState ( State .RESOLVED );
87+ return extractRowState ( (ReactiveEmbeddableInitializerData ) data )
88+ .thenAccept ( unused -> prepareCompositeInstance ( (ReactiveEmbeddableInitializerData ) data ) );
89+ }
90+
91+ private CompletionStage <Void > extractRowState (ReactiveEmbeddableInitializerData data ) {
92+ final DomainResultAssembler <?>[] subAssemblers = assemblers [data .getSubclassId ()];
93+ final RowProcessingState rowProcessingState = data .getRowProcessingState ();
94+ final Object [] rowState = data .getRowState ();
95+ final boolean [] stateAllNull = {true };
96+ final int [] index = {0 };
97+ final boolean [] forceExit = { false };
98+ return whileLoop (
99+ () -> index [0 ] < subAssemblers .length && !forceExit [0 ],
100+ () -> {
101+ final int i = index [0 ]++;
102+ final DomainResultAssembler <?> assembler = subAssemblers [i ];
103+ if ( assembler instanceof ReactiveDomainResultsAssembler <?> reactiveAssembler ) {
104+ return reactiveAssembler .reactiveAssemble ( (ReactiveRowProcessingState ) rowProcessingState )
105+ .thenAccept ( contributorValue -> setContributorValue (
106+ contributorValue ,
107+ i ,
108+ rowState ,
109+ stateAllNull ,
110+ forceExit
111+ ) );
112+ }
113+ else {
114+ setContributorValue (
115+ assembler == null ? null : assembler .assemble ( rowProcessingState ),
116+ i ,
117+ rowState ,
118+ stateAllNull ,
119+ forceExit
120+ );
121+ return voidFuture ();
122+ }
123+ })
124+ .whenComplete (
125+ (unused , throwable ) -> {
126+ if ( stateAllNull [0 ] ) {
127+ data .setState ( State .MISSING );
128+ }
129+ }
130+ );
131+ }
132+
133+ private void setContributorValue (
134+ Object contributorValue ,
135+ int index ,
136+ Object [] rowState ,
137+ boolean [] stateAllNull ,
138+ boolean [] forceExit ) {
139+ if ( contributorValue == BATCH_PROPERTY ) {
140+ rowState [index ] = null ;
141+ }
142+ else {
143+ rowState [index ] = contributorValue ;
144+ }
145+ if ( contributorValue != null ) {
146+ stateAllNull [0 ] = false ;
147+ }
148+ else if ( isPartOfKey () ) {
149+ // If this is a foreign key and there is a null part, the whole thing has to be turned into null
150+ stateAllNull [0 ] = true ;
151+ forceExit [0 ] = true ;
152+ }
153+ }
154+
155+ private CompletionStage <Void > prepareCompositeInstance (ReactiveEmbeddableInitializerData data ) {
156+ // Virtual model parts use the owning entity as container which the fetch parent access provides.
157+ // For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
158+ // so we can't use the fetch parent access in that case.
159+ final ReactiveInitializer <ReactiveEmbeddableInitializerData > parent = (ReactiveInitializer <ReactiveEmbeddableInitializerData >) getParent ();
160+ if ( parent != null && getInitializedPart () instanceof VirtualModelPart && !isPartOfKey () && data .getState () != State .MISSING ) {
161+ final ReactiveEmbeddableInitializerData subData = parent .getData ( data .getRowProcessingState () );
162+ return parent
163+ .reactiveResolveInstance ( subData )
164+ .thenCompose (
165+ unused -> {
166+ data .setInstance ( parent .getResolvedInstance ( subData ) );
167+ if ( data .getState () == State .INITIALIZED ) {
168+ return voidFuture ();
169+ }
170+ return doCreateCompositeInstance ( data )
171+ .thenAccept ( v -> EMBEDDED_LOAD_LOGGER .debugf (
172+ "Created composite instance [%s]" ,
173+ getNavigablePath ()
174+ ) );
175+ } );
176+ }
177+
178+ return doCreateCompositeInstance ( data )
179+ .thenAccept ( v -> EMBEDDED_LOAD_LOGGER .debugf ( "Created composite instance [%s]" , getNavigablePath () ) );
180+
181+ }
182+
183+ private CompletionStage <Void > doCreateCompositeInstance (ReactiveEmbeddableInitializerData data ) {
184+ if ( data .getInstance () == null ) {
185+ return createCompositeInstance ( data )
186+ .thenAccept ( data ::setInstance );
187+ }
68188 return voidFuture ();
69189 }
70190
191+ private CompletionStage <Object > createCompositeInstance (ReactiveEmbeddableInitializerData data ) {
192+ if ( data .getState () == State .MISSING ) {
193+ return nullFuture ();
194+ }
195+
196+ final EmbeddableInstantiator instantiator = data .getConcreteEmbeddableType () == null
197+ ? getInitializedPart ().getEmbeddableTypeDescriptor ().getRepresentationStrategy ().getInstantiator ()
198+ : data .getConcreteEmbeddableType ().getInstantiator ();
199+ final Object instance = instantiator .instantiate ( data );
200+ data .setState ( State .RESOLVED );
201+ return completedFuture ( instance );
202+ }
203+
71204 @ Override
72205 public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73206 super .initializeInstance ( data );
0 commit comments