5
5
*/
6
6
package org .hibernate .reactive .sql .results .graph .embeddable .internal ;
7
7
8
+
8
9
import java .util .concurrent .CompletionStage ;
9
10
import java .util .function .BiFunction ;
11
+ import java .util .function .Supplier ;
10
12
11
13
import 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 ;
12
18
import org .hibernate .reactive .sql .results .graph .ReactiveInitializer ;
13
19
import org .hibernate .sql .results .graph .AssemblerCreationState ;
20
+ import org .hibernate .sql .results .graph .DomainResultAssembler ;
14
21
import org .hibernate .sql .results .graph .Initializer ;
15
22
import org .hibernate .sql .results .graph .InitializerData ;
16
23
import org .hibernate .sql .results .graph .InitializerParent ;
19
26
import org .hibernate .sql .results .graph .embeddable .internal .EmbeddableInitializerImpl ;
20
27
import org .hibernate .sql .results .jdbc .spi .RowProcessingState ;
21
28
29
+ import static org .hibernate .reactive .util .impl .CompletionStages .completedFuture ;
22
30
import static org .hibernate .reactive .util .impl .CompletionStages .loop ;
23
31
import 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 ;
24
34
25
35
public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
26
36
implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
@@ -33,6 +43,14 @@ public ReactiveEmbeddableInitializerData(
33
43
super ( initializer , rowProcessingState );
34
44
}
35
45
46
+ public Object [] getRowState (){
47
+ return rowState ;
48
+ }
49
+
50
+ public EmbeddableMappingType .ConcreteEmbeddableType getEmbeddableType () {
51
+ return concreteEmbeddableType ;
52
+ }
53
+
36
54
@ Override
37
55
public void setState (State state ) {
38
56
super .setState ( state );
@@ -64,10 +82,140 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
64
82
65
83
@ Override
66
84
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
+ }
68
172
return voidFuture ();
69
173
}
70
174
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
+
71
219
@ Override
72
220
public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73
221
super .initializeInstance ( data );
0 commit comments