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
12
+ import org .hibernate .engine .spi .SessionFactoryImplementor ;
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 ;
31
+ import static org .hibernate .reactive .util .impl .CompletionStages .nullFuture ;
23
32
import 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 ;
24
36
25
37
public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl
26
38
implements ReactiveInitializer <EmbeddableInitializerImpl .EmbeddableInitializerData > {
27
39
40
+ private final SessionFactoryImplementor sessionFactory ;
41
+
28
42
private static class ReactiveEmbeddableInitializerData extends EmbeddableInitializerData {
29
43
30
44
public ReactiveEmbeddableInitializerData (
@@ -33,6 +47,10 @@ public ReactiveEmbeddableInitializerData(
33
47
super ( initializer , rowProcessingState );
34
48
}
35
49
50
+ public Object [] getRowState (){
51
+ return rowState ;
52
+ }
53
+
36
54
@ Override
37
55
public void setState (State state ) {
38
56
super .setState ( state );
@@ -55,6 +73,7 @@ public ReactiveEmbeddableInitializerImpl(
55
73
AssemblerCreationState creationState ,
56
74
boolean isResultInitializer ) {
57
75
super ( resultDescriptor , discriminatorFetch , parent , creationState , isResultInitializer );
76
+ sessionFactory = creationState .getSqlAstCreationContext ().getSessionFactory ();
58
77
}
59
78
60
79
@ Override
@@ -64,10 +83,129 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing
64
83
65
84
@ Override
66
85
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
+ }
68
193
return voidFuture ();
69
194
}
70
195
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
+
71
209
@ Override
72
210
public CompletionStage <Void > reactiveInitializeInstance (EmbeddableInitializerData data ) {
73
211
super .initializeInstance ( data );
0 commit comments