2828 * @author Steve Ebersole 
2929 */ 
3030public  class  LazyAttributeLoadingInterceptor  extends  AbstractInterceptor  implements  BytecodeLazyAttributeInterceptor  {
31- 	private  final  Object  identifier ;
32- 	private  final  String  entityName ;
3331
34- 	//N.B. this Set needs to be treated as immutable 
35- 	private  Set < String >  lazyFields ;
32+ 	private   final   Object   identifier ; 
33+ 	private  EntityRelatedState   entityMeta ;
3634	private  Set <String > initializedLazyFields ;
37- 	private  Set <String > mutableLazyFields ;
3835
3936	public  LazyAttributeLoadingInterceptor (
40- 			String   entityName ,
37+ 			EntityRelatedState   entityMeta ,
4138			Object  identifier ,
42- 			Set <String > lazyFields ,
4339			SharedSessionContractImplementor  session ) {
44- 		this .entityName  = entityName ;
4540		this .identifier  = identifier ;
46- 		this .lazyFields  = lazyFields ;
41+ 		this .entityMeta  = entityMeta ;
4742		setSession ( session  );
4843	}
4944
5045	@ Override 
5146	public  String  getEntityName () {
52- 		return  entityName ;
47+ 		return  entityMeta . entityName ;
5348	}
5449
5550	@ Override 
@@ -130,23 +125,23 @@ public boolean isAttributeLoaded(String fieldName) {
130125	}
131126
132127	private  boolean  isLazyAttribute (String  fieldName ) {
133- 		return  lazyFields .contains ( fieldName  );
128+ 		return  entityMeta . lazyFields .contains ( fieldName  );
134129	}
135130
136131	private  boolean  isInitializedLazyField (String  fieldName ) {
137132		return  initializedLazyFields  != null  && initializedLazyFields .contains ( fieldName  );
138133	}
139134
140135	public  boolean  hasAnyUninitializedAttributes () {
141- 		if  ( lazyFields .isEmpty () ) {
136+ 		if  ( entityMeta . lazyFields .isEmpty () ) {
142137			return  false ;
143138		}
144139
145140		if  ( initializedLazyFields  == null  ) {
146141			return  true ;
147142		}
148143
149- 		for  ( String  fieldName  : lazyFields  ) {
144+ 		for  ( String  fieldName  : entityMeta . lazyFields  ) {
150145			if  ( !initializedLazyFields .contains ( fieldName  ) ) {
151146				return  true ;
152147			}
@@ -157,7 +152,7 @@ public boolean hasAnyUninitializedAttributes() {
157152
158153	@ Override 
159154	public  String  toString () {
160- 		return  getClass ().getSimpleName () + "(entityName="  + getEntityName () + " ,lazyFields="  + lazyFields  + ')' ;
155+ 		return  getClass ().getSimpleName () + "(entityName="  + getEntityName () + " ,lazyFields="  + entityMeta . lazyFields  + ')' ;
161156	}
162157
163158	private  void  takeCollectionSizeSnapshot (Object  target , String  fieldName , Object  value ) {
@@ -197,14 +192,43 @@ public Set<String> getInitializedLazyAttributeNames() {
197192	}
198193
199194	public  void  addLazyFieldByGraph (String  fieldName ) {
200- 		if  ( mutableLazyFields  == null  ) {
201- 			mutableLazyFields  = new  HashSet <>( lazyFields  );
202- 			lazyFields  = mutableLazyFields ;
195+ 		if  ( entityMeta .shared  ) {
196+ 			//We need to make a defensive copy first to not affect other entities of the same type; 
197+ 			//as we create a copy we lose some of the efficacy of using a separate class to track this state, 
198+ 			//but this is a corner case so we prefer to optimise for the common case. 
199+ 			entityMeta  = entityMeta .toNonSharedMutableState ();
203200		}
204- 		mutableLazyFields .add ( fieldName  );
201+ 		entityMeta . lazyFields .add ( fieldName  );
205202	}
206203
207204	public  void  clearInitializedLazyFields () {
208205		initializedLazyFields  = null ;
209206	}
207+ 
208+ 	/** 
209+ 	 * This is an helper object to group all state which relates to a particular entity type, 
210+ 	 * and which is needed for this interceptor. 
211+ 	 * Grouping such state allows for upfront construction as a per-entity singleton: 
212+ 	 * this reduces processing work on creation of an interceptor instance and is more 
213+ 	 * efficient from a point of view of memory usage and memory layout. 
214+ 	 */ 
215+ 	public  static  class  EntityRelatedState  {
216+ 		private  final  String  entityName ;
217+ 		private  final  Set <String > lazyFields ;
218+ 		private  final  boolean  shared ;
219+ 
220+ 		public  EntityRelatedState (String  entityName , Set <String > lazyFields ) {
221+ 			this .entityName  = entityName ;
222+ 			this .lazyFields  = lazyFields ; //N.B. this is an immutable, compact set 
223+ 			this .shared  = true ;
224+ 		}
225+ 		private  EntityRelatedState (String  entityName , Set <String > lazyFields , boolean  shared ) {
226+ 			this .entityName  = entityName ;
227+ 			this .lazyFields  = lazyFields ;
228+ 			this .shared  = shared ;
229+ 		}
230+ 		private  EntityRelatedState  toNonSharedMutableState () {
231+ 			return  new  EntityRelatedState ( entityName , new  HashSet <>( lazyFields  ), false  );
232+ 		}
233+ 	}
210234}
0 commit comments