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 @ Override
8848 public String getEntityName () {
89- return entityName ;
49+ return meta . entityName ;
9050 }
9151
9252 public EntityKey getEntityKey () {
@@ -102,7 +62,7 @@ protected Object handleRead(Object target, String attributeName, Object value) {
10262
10363 // the attribute being read is an entity-id attribute
10464 // - we already know the id, return that
105- if ( identifierAttributeNames .contains ( attributeName ) ) {
65+ if ( meta . identifierAttributeNames .contains ( attributeName ) ) {
10666 return extractIdValue ( target , attributeName );
10767 }
10868
@@ -120,14 +80,10 @@ private Object read(
12080 final Object [] writtenAttributeValues ;
12181 final AttributeMapping [] writtenAttributeMappings ;
12282
123- final EntityPersister entityPersister =
124- session .getFactory ().getMappingMetamodel ()
125- .getEntityDescriptor ( getEntityName () );
126-
12783 if ( writtenFieldNames != null && !writtenFieldNames .isEmpty () ) {
12884
12985 // enhancement has dirty-tracking available and at least one attribute was explicitly set
130-
86+ final EntityPersister entityPersister = meta . persister ;
13187 if ( writtenFieldNames .contains ( attributeName ) ) {
13288 // the requested attribute was one of the attributes explicitly set,
13389 // we can just return the explicitly-set value
@@ -162,7 +118,7 @@ private Object read(
162118 for ( int i = 0 ; i < writtenAttributeMappings .length ; i ++ ) {
163119 final AttributeMapping attribute = writtenAttributeMappings [i ];
164120 attribute .setValue (target , writtenAttributeValues [i ] );
165- if ( inLineDirtyChecking ) {
121+ if ( meta . inLineDirtyChecking ) {
166122 asSelfDirtinessTracker (target ).$$_hibernate_trackChange ( attribute .getAttributeName () );
167123 }
168124 }
@@ -174,6 +130,7 @@ private Object read(
174130
175131 private Object extractIdValue (Object target , String attributeName ) {
176132 // access to the id or part of it for non-aggregated cid
133+ final CompositeType nonAggregatedCidMapper = meta .nonAggregatedCidMapper ;
177134 if ( nonAggregatedCidMapper == null ) {
178135 return getIdentifier ();
179136 }
@@ -218,17 +175,13 @@ public Object forceInitialize(
218175 );
219176 }
220177
221- final EntityPersister persister =
222- session .getFactory ().getMappingMetamodel ()
223- .getEntityDescriptor ( getEntityName () );
224-
225178 if ( isTemporarySession ) {
226179 // Add an entry for this entity in the PC of the temp Session
227180 session .getPersistenceContext ()
228181 .addEnhancedProxy ( entityKey , asPersistentAttributeInterceptable ( target ) );
229182 }
230183
231- return persister .initializeEnhancedEntityUsedAsProxy ( target , attributeName , session );
184+ return meta . persister .initializeEnhancedEntityUsedAsProxy ( target , attributeName , session );
232185 }
233186
234187 @ Override
@@ -237,19 +190,19 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
237190 throw new IllegalStateException ( "EnhancementAsProxyLazinessInterceptor interception on an initialized instance" );
238191 }
239192
240- if ( identifierAttributeNames .contains ( attributeName ) ) {
193+ if ( meta . identifierAttributeNames .contains ( attributeName ) ) {
241194 // it is illegal for the identifier value to be changed. Normally Hibernate
242195 // validates this during flush. However, here it's dangerous to just allow the
243196 // new value to be set and continue on waiting for the flush for validation
244197 // because this interceptor manages the entity's entry in the PC itself. So
245198 // just do the check here up-front
246199 final boolean changed ;
247- if ( nonAggregatedCidMapper == null ) {
200+ if ( meta . nonAggregatedCidMapper == null ) {
248201 changed = ! entityKey .getPersister ().getIdentifierType ().isEqual ( oldValue , newValue );
249202 }
250203 else {
251- final int subAttrIndex = nonAggregatedCidMapper .getPropertyIndex ( attributeName );
252- final Type subAttrType = nonAggregatedCidMapper .getSubtypes ()[subAttrIndex ];
204+ final int subAttrIndex = meta . nonAggregatedCidMapper .getPropertyIndex ( attributeName );
205+ final Type subAttrType = meta . nonAggregatedCidMapper .getSubtypes ()[subAttrIndex ];
253206 changed = ! subAttrType .isEqual ( oldValue , newValue );
254207 }
255208
@@ -262,8 +215,8 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
262215 return newValue ;
263216 }
264217
265- if ( initializeBeforeWrite
266- || collectionAttributeNames != null && collectionAttributeNames .contains ( attributeName ) ) {
218+ if ( meta . initializeBeforeWrite
219+ || meta . collectionAttributeNames != null && meta . collectionAttributeNames .contains ( attributeName ) ) {
267220 // we need to force-initialize the proxy - the fetch group to which the `attributeName` belongs
268221 try {
269222 forceInitialize ( target , attributeName );
@@ -272,7 +225,7 @@ protected Object handleWrite(Object target, String attributeName, Object oldValu
272225 setInitialized ();
273226 }
274227
275- if ( inLineDirtyChecking ) {
228+ if ( meta . inLineDirtyChecking ) {
276229 asSelfDirtinessTracker ( target ).$$_hibernate_trackChange ( attributeName );
277230 }
278231 }
@@ -310,7 +263,7 @@ public boolean isAttributeLoaded(String fieldName) {
310263 throw new UnsupportedOperationException ( "Call to EnhancementAsProxyLazinessInterceptor#isAttributeLoaded on an interceptor which is marked as initialized" );
311264 }
312265 // Only fields from the identifier are loaded (until it's initialized)
313- return identifierAttributeNames .contains ( fieldName );
266+ return meta . identifierAttributeNames .contains ( fieldName );
314267 }
315268
316269 @ Override
@@ -352,4 +305,58 @@ private enum Status {
352305 INITIALIZING ,
353306 INITIALIZED
354307 }
308+
309+ /**
310+ * This is an helper object to group all state which relates to a particular entity type,
311+ * and which is needed for this interceptor.
312+ * Grouping such state allows for upfront construction as a per-entity singleton:
313+ * this reduces processing work on creation of an interceptor instance and is more
314+ * efficient from a point of view of memory usage and memory layout.
315+ */
316+ public static class EntityRelatedState {
317+
318+ private final String entityName ;
319+ private final CompositeType nonAggregatedCidMapper ;
320+ private final Set <String > identifierAttributeNames ;
321+ private final Set <String > collectionAttributeNames ;
322+ private final boolean initializeBeforeWrite ;
323+ private final boolean inLineDirtyChecking ;
324+ private final EntityPersister persister ;
325+
326+ public EntityRelatedState (EntityPersister persister ,
327+ CompositeType nonAggregatedCidMapper ,
328+ Set <String > identifierAttributeNames ) {
329+ this .identifierAttributeNames = identifierAttributeNames ;
330+ this .entityName = persister .getEntityName ();
331+ this .nonAggregatedCidMapper = nonAggregatedCidMapper ;
332+ this .persister = persister ;
333+ assert nonAggregatedCidMapper != null || identifierAttributeNames .size () == 1 ;
334+
335+ if ( persister .hasCollections () ) {
336+ final Set <String > tmpCollectionAttributeNames = new HashSet <>();
337+ final Type [] propertyTypes = persister .getPropertyTypes ();
338+ final String [] propertyNames = persister .getPropertyNames ();
339+ for ( int i = 0 ; i < propertyTypes .length ; i ++ ) {
340+ Type propertyType = propertyTypes [i ];
341+ if ( propertyType instanceof CollectionType ) {
342+ tmpCollectionAttributeNames .add ( propertyNames [i ] );
343+ }
344+ }
345+ this .collectionAttributeNames = toSmallSet ( unmodifiableSet ( tmpCollectionAttributeNames ) );
346+ }
347+ else {
348+ this .collectionAttributeNames = Collections .emptySet ();
349+ }
350+
351+ this .inLineDirtyChecking = isSelfDirtinessTrackerType ( persister .getMappedClass () );
352+ // if self-dirty tracking is enabled but DynamicUpdate is not enabled then we need to
353+ // initialize the entity because the precomputed update statement contains even not
354+ // dirty properties. And so we need all the values we have to initialize. Or, if it's
355+ // versioned, we need to fetch the current version.
356+ this .initializeBeforeWrite =
357+ !inLineDirtyChecking
358+ || !persister .getEntityMetamodel ().isDynamicUpdate ()
359+ || persister .isVersioned ();
360+ }
361+ }
355362}
0 commit comments