1818import org .hibernate .type .CompositeType ;
1919import org .hibernate .type .Type ;
2020
21+ import static java .util .Collections .unmodifiableSet ;
2122import static org .hibernate .engine .internal .ManagedTypeHelper .asPersistentAttributeInterceptable ;
2223import static org .hibernate .engine .internal .ManagedTypeHelper .asSelfDirtinessTracker ;
2324import static org .hibernate .engine .internal .ManagedTypeHelper .isSelfDirtinessTrackerType ;
25+ import static org .hibernate .internal .util .collections .CollectionHelper .toSmallSet ;
2426
2527/**
2628 * @author Steve Ebersole
2729 */
2830public class EnhancementAsProxyLazinessInterceptor extends AbstractInterceptor implements BytecodeLazyAttributeInterceptor {
29- private final Set <String > identifierAttributeNames ;
30- private final CompositeType nonAggregatedCidMapper ;
31- private final String entityName ;
3231
3332 private final EntityKey entityKey ;
34-
35- private final boolean inLineDirtyChecking ;
33+ private final EntityRelatedState meta ;
3634 private Set <String > writtenFieldNames ;
37- private Set <String > collectionAttributeNames ;
38-
3935 private Status status ;
4036
41- private final boolean initializeBeforeWrite ;
42-
4337 public EnhancementAsProxyLazinessInterceptor (
44- String entityName ,
45- Set <String > identifierAttributeNames ,
46- CompositeType nonAggregatedCidMapper ,
38+ EntityRelatedState meta ,
4739 EntityKey entityKey ,
4840 SharedSessionContractImplementor session ) {
49- this .entityName = entityName ;
50-
51- this .identifierAttributeNames = identifierAttributeNames ;
52- assert identifierAttributeNames != null ;
53-
54- this .nonAggregatedCidMapper = nonAggregatedCidMapper ;
55- assert nonAggregatedCidMapper != null || identifierAttributeNames .size () == 1 ;
56-
5741 this .entityKey = entityKey ;
58- setSession ( session );
59-
60- final EntityPersister entityPersister =
61- session .getFactory ().getMappingMetamodel ()
62- .getEntityDescriptor ( entityName );
63- if ( entityPersister .hasCollections () ) {
64- final Type [] propertyTypes = entityPersister .getPropertyTypes ();
65- final String [] propertyNames = entityPersister .getPropertyNames ();
66- collectionAttributeNames = new HashSet <>();
67- for ( int i = 0 ; i < propertyTypes .length ; i ++ ) {
68- Type propertyType = propertyTypes [i ];
69- if ( propertyType instanceof CollectionType ) {
70- collectionAttributeNames .add ( propertyNames [i ] );
71- }
72- }
73- }
74-
75- this .inLineDirtyChecking = isSelfDirtinessTrackerType ( entityPersister .getMappedClass () );
76- // if self-dirty tracking is enabled but DynamicUpdate is not enabled then we need to
77- // initialize the entity because the precomputed update statement contains even not
78- // dirty properties. And so we need all the values we have to initialize. Or, if it's
79- // versioned, we need to fetch the current version.
80- initializeBeforeWrite =
81- !inLineDirtyChecking
82- || !entityPersister .getEntityMetamodel ().isDynamicUpdate ()
83- || entityPersister .isVersioned ();
42+ this .meta = meta ;
8443 status = Status .UNINITIALIZED ;
44+ setSession ( session );
8545 }
8646
8747 public String getEntityName () {
88- return entityName ;
48+ return meta . entityName ;
8949 }
9050
9151 public EntityKey getEntityKey () {
@@ -101,7 +61,7 @@ protected Object handleRead(Object target, String attributeName, Object value) {
10161
10262 // the attribute being read is an entity-id attribute
10363 // - we already know the id, return that
104- if ( identifierAttributeNames .contains ( attributeName ) ) {
64+ if ( meta . identifierAttributeNames .contains ( attributeName ) ) {
10565 return extractIdValue ( target , attributeName );
10666 }
10767
@@ -119,14 +79,10 @@ private Object read(
11979 final Object [] writtenAttributeValues ;
12080 final AttributeMapping [] writtenAttributeMappings ;
12181
122- final EntityPersister entityPersister =
123- session .getFactory ().getMappingMetamodel ()
124- .getEntityDescriptor ( getEntityName () );
125-
12682 if ( writtenFieldNames != null && !writtenFieldNames .isEmpty () ) {
12783
12884 // enhancement has dirty-tracking available and at least one attribute was explicitly set
129-
85+ final EntityPersister entityPersister = meta . persister ;
13086 if ( writtenFieldNames .contains ( attributeName ) ) {
13187 // the requested attribute was one of the attributes explicitly set,
13288 // we can just return the explicitly-set value
@@ -161,7 +117,7 @@ private Object read(
161117 for ( int i = 0 ; i < writtenAttributeMappings .length ; i ++ ) {
162118 final AttributeMapping attribute = writtenAttributeMappings [i ];
163119 attribute .setValue (target , writtenAttributeValues [i ] );
164- if ( inLineDirtyChecking ) {
120+ if ( meta . inLineDirtyChecking ) {
165121 asSelfDirtinessTracker (target ).$$_hibernate_trackChange ( attribute .getAttributeName () );
166122 }
167123 }
@@ -173,6 +129,7 @@ private Object read(
173129
174130 private Object extractIdValue (Object target , String attributeName ) {
175131 // access to the id or part of it for non-aggregated cid
132+ final CompositeType nonAggregatedCidMapper = meta .nonAggregatedCidMapper ;
176133 if ( nonAggregatedCidMapper == null ) {
177134 return getIdentifier ();
178135 }
@@ -217,17 +174,13 @@ public Object forceInitialize(
217174 );
218175 }
219176
220- final EntityPersister persister =
221- session .getFactory ().getMappingMetamodel ()
222- .getEntityDescriptor ( getEntityName () );
223-
224177 if ( isTemporarySession ) {
225178 // Add an entry for this entity in the PC of the temp Session
226179 session .getPersistenceContext ()
227180 .addEnhancedProxy ( entityKey , asPersistentAttributeInterceptable ( target ) );
228181 }
229182
230- return persister .initializeEnhancedEntityUsedAsProxy ( target , attributeName , session );
183+ return meta . persister .initializeEnhancedEntityUsedAsProxy ( target , attributeName , session );
231184 }
232185
233186 @ Override
@@ -236,19 +189,19 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
236189 throw new IllegalStateException ( "EnhancementAsProxyLazinessInterceptor interception on an initialized instance" );
237190 }
238191
239- if ( identifierAttributeNames .contains ( attributeName ) ) {
192+ if ( meta . identifierAttributeNames .contains ( attributeName ) ) {
240193 // it is illegal for the identifier value to be changed. Normally Hibernate
241194 // validates this during flush. However, here it's dangerous to just allow the
242195 // new value to be set and continue on waiting for the flush for validation
243196 // because this interceptor manages the entity's entry in the PC itself. So
244197 // just do the check here up-front
245198 final boolean changed ;
246- if ( nonAggregatedCidMapper == null ) {
199+ if ( meta . nonAggregatedCidMapper == null ) {
247200 changed = ! entityKey .getPersister ().getIdentifierType ().isEqual ( oldValue , newValue );
248201 }
249202 else {
250- final int subAttrIndex = nonAggregatedCidMapper .getPropertyIndex ( attributeName );
251- final Type subAttrType = nonAggregatedCidMapper .getSubtypes ()[subAttrIndex ];
203+ final int subAttrIndex = meta . nonAggregatedCidMapper .getPropertyIndex ( attributeName );
204+ final Type subAttrType = meta . nonAggregatedCidMapper .getSubtypes ()[subAttrIndex ];
252205 changed = ! subAttrType .isEqual ( oldValue , newValue );
253206 }
254207
@@ -261,8 +214,8 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
261214 return newValue ;
262215 }
263216
264- if ( initializeBeforeWrite
265- || collectionAttributeNames != null && collectionAttributeNames .contains ( attributeName ) ) {
217+ if ( meta . initializeBeforeWrite
218+ || meta . collectionAttributeNames != null && meta . collectionAttributeNames .contains ( attributeName ) ) {
266219 // we need to force-initialize the proxy - the fetch group to which the `attributeName` belongs
267220 try {
268221 forceInitialize ( target , attributeName );
@@ -271,7 +224,7 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
271224 setInitialized ();
272225 }
273226
274- if ( inLineDirtyChecking ) {
227+ if ( meta . inLineDirtyChecking ) {
275228 asSelfDirtinessTracker ( target ).$$_hibernate_trackChange ( attributeName );
276229 }
277230 }
@@ -309,7 +262,7 @@ public boolean isAttributeLoaded(String fieldName) {
309262 throw new UnsupportedOperationException ( "Call to EnhancementAsProxyLazinessInterceptor#isAttributeLoaded on an interceptor which is marked as initialized" );
310263 }
311264 // Only fields from the identifier are loaded (until it's initialized)
312- return identifierAttributeNames .contains ( fieldName );
265+ return meta . identifierAttributeNames .contains ( fieldName );
313266 }
314267
315268 @ Override
@@ -351,4 +304,58 @@ private enum Status {
351304 INITIALIZING ,
352305 INITIALIZED
353306 }
307+
308+ /**
309+ * This is an helper object to group all state which relates to a particular entity type,
310+ * and which is needed for this interceptor.
311+ * Grouping such state allows for upfront construction as a per-entity singleton:
312+ * this reduces processing work on creation of an interceptor instance and is more
313+ * efficient from a point of view of memory usage and memory layout.
314+ */
315+ public static class EntityRelatedState {
316+
317+ private final String entityName ;
318+ private final CompositeType nonAggregatedCidMapper ;
319+ private final Set <String > identifierAttributeNames ;
320+ private final Set <String > collectionAttributeNames ;
321+ private final boolean initializeBeforeWrite ;
322+ private final boolean inLineDirtyChecking ;
323+ private final EntityPersister persister ;
324+
325+ public EntityRelatedState (EntityPersister persister ,
326+ CompositeType nonAggregatedCidMapper ,
327+ Set <String > identifierAttributeNames ) {
328+ this .identifierAttributeNames = identifierAttributeNames ;
329+ this .entityName = persister .getEntityName ();
330+ this .nonAggregatedCidMapper = nonAggregatedCidMapper ;
331+ this .persister = persister ;
332+ assert nonAggregatedCidMapper != null || identifierAttributeNames .size () == 1 ;
333+
334+ if ( persister .hasCollections () ) {
335+ final Set <String > tmpCollectionAttributeNames = new HashSet <>();
336+ final Type [] propertyTypes = persister .getPropertyTypes ();
337+ final String [] propertyNames = persister .getPropertyNames ();
338+ for ( int i = 0 ; i < propertyTypes .length ; i ++ ) {
339+ Type propertyType = propertyTypes [i ];
340+ if ( propertyType instanceof CollectionType ) {
341+ tmpCollectionAttributeNames .add ( propertyNames [i ] );
342+ }
343+ }
344+ this .collectionAttributeNames = toSmallSet ( unmodifiableSet ( tmpCollectionAttributeNames ) );
345+ }
346+ else {
347+ this .collectionAttributeNames = Collections .emptySet ();
348+ }
349+
350+ this .inLineDirtyChecking = isSelfDirtinessTrackerType ( persister .getMappedClass () );
351+ // if self-dirty tracking is enabled but DynamicUpdate is not enabled then we need to
352+ // initialize the entity because the precomputed update statement contains even not
353+ // dirty properties. And so we need all the values we have to initialize. Or, if it's
354+ // versioned, we need to fetch the current version.
355+ this .initializeBeforeWrite =
356+ !inLineDirtyChecking
357+ || !persister .getEntityMetamodel ().isDynamicUpdate ()
358+ || persister .isVersioned ();
359+ }
360+ }
354361}
0 commit comments