4949import org .hibernate .loader .plan .spi .Return ;
5050import org .hibernate .persister .walking .spi .AssociationAttributeDefinition ;
5151import org .hibernate .persister .walking .spi .AttributeDefinition ;
52- import org .hibernate .persister .walking .spi .CollectionDefinition ;
5352import org .hibernate .persister .walking .spi .CollectionElementDefinition ;
5453import org .hibernate .persister .walking .spi .CollectionIndexDefinition ;
55- import org .hibernate .persister .walking .spi .CompositionDefinition ;
5654import org .hibernate .persister .walking .spi .EntityDefinition ;
5755import org .hibernate .persister .walking .spi .WalkingException ;
5856import org .jboss .logging .Logger ;
7371 * it is not, then depends on which property is used to apply this entity graph.
7472 *
7573 * @author Strong Liu <stliu@hibernate.org>
74+ * @author Brett Meyer
7675 */
7776public abstract class AbstractEntityGraphVisitationStrategy
7877 extends AbstractLoadPlanBuildingAssociationVisitationStrategy {
@@ -87,10 +86,14 @@ public abstract class AbstractEntityGraphVisitationStrategy
8786 protected static final FetchStrategy DEFAULT_EAGER = new FetchStrategy ( FetchTiming .IMMEDIATE , FetchStyle .JOIN );
8887 protected static final FetchStrategy DEFAULT_LAZY = new FetchStrategy ( FetchTiming .DELAYED , FetchStyle .SELECT );
8988 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 >>();
9497 private EntityReturn rootEntityReturn ;
9598 private final LockMode lockMode ;
9699
@@ -106,24 +109,21 @@ protected AbstractEntityGraphVisitationStrategy(
106109 public void start () {
107110 super .start ();
108111 graphStack .addLast ( getRootEntityGraph () );
109- attributeNodeImplementorMap = buildAttributeNodeMap ();
110112 }
111113
112114 @ Override
113115 public void finish () {
114116 super .finish ();
115117 graphStack .removeLast ();
116- attributeNodeImplementorMap = Collections .emptyMap ();
117118 //applying a little internal stack checking
118- if ( !graphStack .isEmpty () || !attributeStack .isEmpty () || !attributeNodeImplementorMap .isEmpty () ) {
119+ if ( !graphStack .isEmpty () || !attributeStack .isEmpty () || !attributeMapStack .isEmpty () ) {
119120 throw new WalkingException ( "Internal stack error" );
120121 }
121122 }
122123
123124 @ Override
124125 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 () );
127127 super .startingEntity ( entityDefinition );
128128 }
129129
@@ -143,6 +143,12 @@ protected Map<String, AttributeNodeImplementor> buildAttributeNodeMap() {
143143 return attributeNodeImplementorMap ;
144144 }
145145
146+ @ Override
147+ public void finishingEntity (final EntityDefinition entityDefinition ) {
148+ attributeMapStack .removeLast ();
149+ super .finishingEntity ( entityDefinition );
150+ }
151+
146152 /**
147153 * I'm using NULL-OBJECT pattern here, for attributes that not existing in the EntityGraph,
148154 * a predefined NULL-ATTRIBUTE-NODE is pushed to the stack.
@@ -156,12 +162,13 @@ protected Map<String, AttributeNodeImplementor> buildAttributeNodeMap() {
156162 */
157163 @ Override
158164 public boolean startingAttribute (AttributeDefinition attributeDefinition ) {
165+ Map <String , AttributeNodeImplementor > attributeMap = attributeMapStack .peekLast ();
159166 final String attrName = attributeDefinition .getName ();
160167 AttributeNodeImplementor attributeNode = NON_EXIST_ATTRIBUTE_NODE ;
161168 GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE ;
162169 //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 );
165172 //here we need to check if there is a subgraph (or sub key graph if it is an indexed attribute )
166173 Map <Class , Subgraph > subGraphs = attributeNode .getSubgraphs ();
167174 Class javaType = attributeDefinition .getType ().getReturnedClass ();
@@ -183,52 +190,26 @@ public void finishingAttribute(final AttributeDefinition attributeDefinition) {
183190 super .finishingAttribute ( attributeDefinition );
184191 }
185192
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-
221193
222194 @ Override
223195 public void startingCollectionElements (
224196 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 );
225205 super .startingCollectionElements ( elementDefinition );
226206 }
227207
228208 @ Override
229209 public void finishingCollectionElements (
230210 final CollectionElementDefinition elementDefinition ) {
231211 super .finishingCollectionElements ( elementDefinition );
212+ graphStack .removeLast ();
232213 }
233214
234215
0 commit comments