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