49
49
import org .hibernate .loader .plan .spi .Return ;
50
50
import org .hibernate .persister .walking .spi .AssociationAttributeDefinition ;
51
51
import org .hibernate .persister .walking .spi .AttributeDefinition ;
52
- import org .hibernate .persister .walking .spi .CollectionDefinition ;
53
52
import org .hibernate .persister .walking .spi .CollectionElementDefinition ;
54
53
import org .hibernate .persister .walking .spi .CollectionIndexDefinition ;
55
- import org .hibernate .persister .walking .spi .CompositionDefinition ;
56
54
import org .hibernate .persister .walking .spi .EntityDefinition ;
57
55
import org .hibernate .persister .walking .spi .WalkingException ;
58
56
import org .jboss .logging .Logger ;
73
71
* it is not, then depends on which property is used to apply this entity graph.
74
72
*
75
73
* @author Strong Liu <[email protected] >
74
+ * @author Brett Meyer
76
75
*/
77
76
public abstract class AbstractEntityGraphVisitationStrategy
78
77
extends AbstractLoadPlanBuildingAssociationVisitationStrategy {
@@ -87,10 +86,14 @@ public abstract class AbstractEntityGraphVisitationStrategy
87
86
protected static final FetchStrategy DEFAULT_EAGER = new FetchStrategy ( FetchTiming .IMMEDIATE , FetchStyle .JOIN );
88
87
protected static final FetchStrategy DEFAULT_LAZY = new FetchStrategy ( FetchTiming .DELAYED , FetchStyle .SELECT );
89
88
protected final LoadQueryInfluencers loadQueryInfluencers ;
90
- protected final ArrayDeque <GraphNodeImplementor > graphStack = new ArrayDeque <GraphNodeImplementor >();
91
- protected final ArrayDeque <AttributeNodeImplementor > attributeStack = new ArrayDeque <AttributeNodeImplementor >();
92
- //the attribute nodes defined in the current graph node (entity graph or subgraph) we're working on
93
- protected Map <String , AttributeNodeImplementor > attributeNodeImplementorMap = Collections .emptyMap ();
89
+ // Queue containing entity/sub graphs to be visited.
90
+ private final ArrayDeque <GraphNodeImplementor > graphStack = new ArrayDeque <GraphNodeImplementor >();
91
+ // Queue containing attributes being visited, used eventually to determine the fetch strategy.
92
+ private final ArrayDeque <AttributeNodeImplementor > attributeStack = new ArrayDeque <AttributeNodeImplementor >();
93
+ // Queue of maps containing the current graph node's attributes. Used for fast lookup, instead of iterating
94
+ // over graphStack.peekLast().attributeImplementorNodes().
95
+ private final ArrayDeque <Map <String , AttributeNodeImplementor >> attributeMapStack
96
+ = new ArrayDeque <Map <String , AttributeNodeImplementor >>();
94
97
private EntityReturn rootEntityReturn ;
95
98
private final LockMode lockMode ;
96
99
@@ -106,24 +109,21 @@ protected AbstractEntityGraphVisitationStrategy(
106
109
public void start () {
107
110
super .start ();
108
111
graphStack .addLast ( getRootEntityGraph () );
109
- attributeNodeImplementorMap = buildAttributeNodeMap ();
110
112
}
111
113
112
114
@ Override
113
115
public void finish () {
114
116
super .finish ();
115
117
graphStack .removeLast ();
116
- attributeNodeImplementorMap = Collections .emptyMap ();
117
118
//applying a little internal stack checking
118
- if ( !graphStack .isEmpty () || !attributeStack .isEmpty () || !attributeNodeImplementorMap .isEmpty () ) {
119
+ if ( !graphStack .isEmpty () || !attributeStack .isEmpty () || !attributeMapStack .isEmpty () ) {
119
120
throw new WalkingException ( "Internal stack error" );
120
121
}
121
122
}
122
123
123
124
@ Override
124
125
public void startingEntity (final EntityDefinition entityDefinition ) {
125
- //TODO check if the passed in entity definition is the same as the root entity graph (a.k.a they are came from same entity class)?
126
- //this maybe the root entity graph or a sub graph.
126
+ attributeMapStack .addLast ( buildAttributeNodeMap () );
127
127
super .startingEntity ( entityDefinition );
128
128
}
129
129
@@ -143,6 +143,12 @@ protected Map<String, AttributeNodeImplementor> buildAttributeNodeMap() {
143
143
return attributeNodeImplementorMap ;
144
144
}
145
145
146
+ @ Override
147
+ public void finishingEntity (final EntityDefinition entityDefinition ) {
148
+ attributeMapStack .removeLast ();
149
+ super .finishingEntity ( entityDefinition );
150
+ }
151
+
146
152
/**
147
153
* I'm using NULL-OBJECT pattern here, for attributes that not existing in the EntityGraph,
148
154
* a predefined NULL-ATTRIBUTE-NODE is pushed to the stack.
@@ -156,12 +162,13 @@ protected Map<String, AttributeNodeImplementor> buildAttributeNodeMap() {
156
162
*/
157
163
@ Override
158
164
public boolean startingAttribute (AttributeDefinition attributeDefinition ) {
165
+ Map <String , AttributeNodeImplementor > attributeMap = attributeMapStack .peekLast ();
159
166
final String attrName = attributeDefinition .getName ();
160
167
AttributeNodeImplementor attributeNode = NON_EXIST_ATTRIBUTE_NODE ;
161
168
GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE ;
162
169
//the attribute is in the EntityGraph, so, let's continue
163
- if ( attributeNodeImplementorMap .containsKey ( attrName ) ) {
164
- attributeNode = attributeNodeImplementorMap .get ( attrName );
170
+ if ( attributeMap .containsKey ( attrName ) ) {
171
+ attributeNode = attributeMap .get ( attrName );
165
172
//here we need to check if there is a subgraph (or sub key graph if it is an indexed attribute )
166
173
Map <Class , Subgraph > subGraphs = attributeNode .getSubgraphs ();
167
174
Class javaType = attributeDefinition .getType ().getReturnedClass ();
@@ -183,52 +190,26 @@ public void finishingAttribute(final AttributeDefinition attributeDefinition) {
183
190
super .finishingAttribute ( attributeDefinition );
184
191
}
185
192
186
- @ Override
187
- protected boolean handleAssociationAttribute (
188
- final AssociationAttributeDefinition attributeDefinition ) {
189
- return super .handleAssociationAttribute ( attributeDefinition );
190
- }
191
-
192
- @ Override
193
- protected boolean handleCompositeAttribute (
194
- final AttributeDefinition attributeDefinition ) {
195
- return super .handleCompositeAttribute ( attributeDefinition );
196
- }
197
-
198
-
199
- @ Override
200
- public void startingComposite (final CompositionDefinition compositionDefinition ) {
201
- super .startingComposite ( compositionDefinition );
202
- }
203
-
204
-
205
- @ Override
206
- public void finishingComposite (final CompositionDefinition compositionDefinition ) {
207
- super .finishingComposite ( compositionDefinition );
208
- }
209
-
210
-
211
- @ Override
212
- public void startingCollection (final CollectionDefinition collectionDefinition ) {
213
- super .startingCollection ( collectionDefinition );
214
- }
215
-
216
- @ Override
217
- public void finishingCollection (final CollectionDefinition collectionDefinition ) {
218
- super .finishingCollection ( collectionDefinition );
219
- }
220
-
221
193
222
194
@ Override
223
195
public void startingCollectionElements (
224
196
final CollectionElementDefinition elementDefinition ) {
197
+ AttributeNodeImplementor attributeNode = attributeStack .peekLast ();
198
+ GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE ;
199
+ Map <Class , Subgraph > subGraphs = attributeNode .getSubgraphs ();
200
+ Class javaType = elementDefinition .getType ().getReturnedClass ();
201
+ if ( !subGraphs .isEmpty () && subGraphs .containsKey ( javaType ) ) {
202
+ subGraphNode = (GraphNodeImplementor ) subGraphs .get ( javaType );
203
+ }
204
+ graphStack .addLast ( subGraphNode );
225
205
super .startingCollectionElements ( elementDefinition );
226
206
}
227
207
228
208
@ Override
229
209
public void finishingCollectionElements (
230
210
final CollectionElementDefinition elementDefinition ) {
231
211
super .finishingCollectionElements ( elementDefinition );
212
+ graphStack .removeLast ();
232
213
}
233
214
234
215
0 commit comments