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 ;
10
11
11
12
import 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 ;
12
17
import org .hibernate .reactive .sql .results .graph .ReactiveInitializer ;
13
18
import org .hibernate .sql .results .graph .AssemblerCreationState ;
19
+ import org .hibernate .sql .results .graph .DomainResultAssembler ;
14
20
import org .hibernate .sql .results .graph .Initializer ;
15
21
import org .hibernate .sql .results .graph .InitializerData ;
16
22
import org .hibernate .sql .results .graph .InitializerParent ;
19
25
import org .hibernate .sql .results .graph .embeddable .internal .EmbeddableInitializerImpl ;
20
26
import org .hibernate .sql .results .jdbc .spi .RowProcessingState ;
21
27
28
+ import static org .hibernate .reactive .util .impl .CompletionStages .completedFuture ;
22
29
import static org .hibernate .reactive .util .impl .CompletionStages .loop ;
30
+ import static org .hibernate .reactive .util .impl .CompletionStages .nullFuture ;
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 .embeddable .EmbeddableLoadingLogger .EMBEDDED_LOAD_LOGGER ;
34
+ import static org .hibernate .sql .results .graph .entity .internal .BatchEntityInsideEmbeddableSelectFetchInitializer .BATCH_PROPERTY ;
24
35
25
36
public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
26
37
implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
@@ -33,6 +44,10 @@ public ReactiveEmbeddableInitializerData(
33
44
super ( initializer , rowProcessingState );
34
45
}
35
46
47
+ public Object [] getRowState (){
48
+ return rowState ;
49
+ }
50
+
36
51
@ Override
37
52
public void setState (State state ) {
38
53
super .setState ( state );
@@ -64,10 +79,128 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
64
79
65
80
@ Override
66
81
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
+ }
68
188
return voidFuture ();
69
189
}
70
190
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
+
71
204
@ Override
72
205
public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73
206
super .initializeInstance ( data );
0 commit comments