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 public String getEntityName () {
51- return entityName ;
46+ return entityMeta . entityName ;
5247 }
5348
5449 @ Override
@@ -129,23 +124,23 @@ public boolean isAttributeLoaded(String fieldName) {
129124 }
130125
131126 private boolean isLazyAttribute (String fieldName ) {
132- return lazyFields .contains ( fieldName );
127+ return entityMeta . lazyFields .contains ( fieldName );
133128 }
134129
135130 private boolean isInitializedLazyField (String fieldName ) {
136131 return initializedLazyFields != null && initializedLazyFields .contains ( fieldName );
137132 }
138133
139134 public boolean hasAnyUninitializedAttributes () {
140- if ( lazyFields .isEmpty () ) {
135+ if ( entityMeta . lazyFields .isEmpty () ) {
141136 return false ;
142137 }
143138
144139 if ( initializedLazyFields == null ) {
145140 return true ;
146141 }
147142
148- for ( String fieldName : lazyFields ) {
143+ for ( String fieldName : entityMeta . lazyFields ) {
149144 if ( !initializedLazyFields .contains ( fieldName ) ) {
150145 return true ;
151146 }
@@ -156,7 +151,7 @@ public boolean hasAnyUninitializedAttributes() {
156151
157152 @ Override
158153 public String toString () {
159- return getClass ().getSimpleName () + "(entityName=" + getEntityName () + " ,lazyFields=" + lazyFields + ')' ;
154+ return getClass ().getSimpleName () + "(entityName=" + getEntityName () + " ,lazyFields=" + entityMeta . lazyFields + ')' ;
160155 }
161156
162157 private void takeCollectionSizeSnapshot (Object target , String fieldName , Object value ) {
@@ -196,14 +191,43 @@ public Set<String> getInitializedLazyAttributeNames() {
196191 }
197192
198193 public void addLazyFieldByGraph (String fieldName ) {
199- if ( mutableLazyFields == null ) {
200- mutableLazyFields = new HashSet <>( lazyFields );
201- lazyFields = mutableLazyFields ;
194+ if ( entityMeta .shared ) {
195+ //We need to make a defensive copy first to not affect other entities of the same type;
196+ //as we create a copy we lose some of the efficacy of using a separate class to track this state,
197+ //but this is a corner case so we prefer to optimise for the common case.
198+ entityMeta = entityMeta .toNonSharedMutableState ();
202199 }
203- mutableLazyFields .add ( fieldName );
200+ entityMeta . lazyFields .add ( fieldName );
204201 }
205202
206203 public void clearInitializedLazyFields () {
207204 initializedLazyFields = null ;
208205 }
206+
207+ /**
208+ * This is an helper object to group all state which relates to a particular entity type,
209+ * and which is needed for this interceptor.
210+ * Grouping such state allows for upfront construction as a per-entity singleton:
211+ * this reduces processing work on creation of an interceptor instance and is more
212+ * efficient from a point of view of memory usage and memory layout.
213+ */
214+ public static class EntityRelatedState {
215+ private final String entityName ;
216+ private final Set <String > lazyFields ;
217+ private final boolean shared ;
218+
219+ public EntityRelatedState (String entityName , Set <String > lazyFields ) {
220+ this .entityName = entityName ;
221+ this .lazyFields = lazyFields ; //N.B. this is an immutable, compact set
222+ this .shared = true ;
223+ }
224+ private EntityRelatedState (String entityName , Set <String > lazyFields , boolean shared ) {
225+ this .entityName = entityName ;
226+ this .lazyFields = lazyFields ;
227+ this .shared = shared ;
228+ }
229+ private EntityRelatedState toNonSharedMutableState () {
230+ return new EntityRelatedState ( entityName , new HashSet <>( lazyFields ), false );
231+ }
232+ }
209233}
0 commit comments