Skip to content

Commit 6c5b2a5

Browse files
committed
Rework all state belonging to LazyAttributeLoadingInterceptor to allow upfront processing
1 parent ef7bb9f commit 6c5b2a5

File tree

4 files changed

+72
-31
lines changed

4 files changed

+72
-31
lines changed

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,22 @@
2828
* @author Steve Ebersole
2929
*/
3030
public 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
}

hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeEnhancementMetadataPojoImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public static BytecodeEnhancementMetadata from(
7272
private final CompositeType nonAggregatedCidMapper;
7373
private final boolean enhancedForLazyLoading;
7474
private final LazyAttributesMetadata lazyAttributesMetadata;
75+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
7576

7677
BytecodeEnhancementMetadataPojoImpl(
7778
String entityName,
@@ -89,6 +90,8 @@ public static BytecodeEnhancementMetadata from(
8990
this.identifierAttributeNames = identifierAttributeNames;
9091
this.enhancedForLazyLoading = enhancedForLazyLoading;
9192
this.lazyAttributesMetadata = lazyAttributesMetadata;
93+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
94+
getEntityName(), lazyAttributesMetadata.getLazyAttributeNames() );
9295
}
9396

9497
@Override
@@ -217,9 +220,8 @@ public LazyAttributeLoadingInterceptor injectInterceptor(
217220
);
218221
}
219222
final LazyAttributeLoadingInterceptor interceptor = new LazyAttributeLoadingInterceptor(
220-
getEntityName(),
223+
this.loadingInterceptorState,
221224
identifier,
222-
lazyAttributesMetadata.getLazyAttributeNames(),
223225
session
224226
);
225227

hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractEntityInstantiatorPojo.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public abstract class AbstractEntityInstantiatorPojo extends AbstractPojoInstant
2323
private final EntityMetamodel entityMetamodel;
2424
private final Class<?> proxyInterface;
2525
private final boolean applyBytecodeInterception;
26+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
2627

2728
public AbstractEntityInstantiatorPojo(
2829
EntityMetamodel entityMetamodel,
@@ -34,17 +35,25 @@ public AbstractEntityInstantiatorPojo(
3435
//TODO this PojoEntityInstantiator appears to not be reused ?!
3536
this.applyBytecodeInterception =
3637
isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
38+
if ( applyBytecodeInterception ) {
39+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
40+
entityMetamodel.getName(),
41+
entityMetamodel.getBytecodeEnhancementMetadata()
42+
.getLazyAttributesMetadata()
43+
.getLazyAttributeNames()
44+
);
45+
}
46+
else {
47+
this.loadingInterceptorState = null;
48+
}
3749
}
3850

3951
protected Object applyInterception(Object entity) {
4052
if ( applyBytecodeInterception ) {
4153
asPersistentAttributeInterceptable( entity )
4254
.$$_hibernate_setInterceptor( new LazyAttributeLoadingInterceptor(
43-
entityMetamodel.getName(),
55+
loadingInterceptorState,
4456
null,
45-
entityMetamodel.getBytecodeEnhancementMetadata()
46-
.getLazyAttributesMetadata()
47-
.getLazyAttributeNames(),
4857
null
4958
) );
5059
}

hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityInstantiatorPojoStandard.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,30 @@
2525
public class EntityInstantiatorPojoStandard extends AbstractEntityInstantiatorPojo {
2626
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityInstantiatorPojoStandard.class );
2727

28-
private final EntityMetamodel entityMetamodel;
2928
private final Class<?> proxyInterface;
3029
private final boolean applyBytecodeInterception;
31-
30+
private final LazyAttributeLoadingInterceptor.EntityRelatedState loadingInterceptorState;
3231
private final Constructor<?> constructor;
3332

3433
public EntityInstantiatorPojoStandard(
3534
EntityMetamodel entityMetamodel,
3635
PersistentClass persistentClass,
3736
JavaType<?> javaType) {
3837
super( entityMetamodel, persistentClass, javaType );
39-
this.entityMetamodel = entityMetamodel;
4038
proxyInterface = persistentClass.getProxyInterface();
4139
constructor = isAbstract() ? null : resolveConstructor( getMappedPojoClass() );
4240
applyBytecodeInterception = isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
41+
if ( applyBytecodeInterception ) {
42+
this.loadingInterceptorState = new LazyAttributeLoadingInterceptor.EntityRelatedState(
43+
entityMetamodel.getName(),
44+
entityMetamodel.getBytecodeEnhancementMetadata()
45+
.getLazyAttributesMetadata()
46+
.getLazyAttributeNames()
47+
);
48+
}
49+
else {
50+
this.loadingInterceptorState = null;
51+
}
4352
}
4453

4554
protected static Constructor<?> resolveConstructor(Class<?> mappedPojoClass) {
@@ -62,11 +71,8 @@ protected Object applyInterception(Object entity) {
6271
if ( applyBytecodeInterception ) {
6372
asPersistentAttributeInterceptable( entity )
6473
.$$_hibernate_setInterceptor( new LazyAttributeLoadingInterceptor(
65-
entityMetamodel.getName(),
74+
loadingInterceptorState,
6675
null,
67-
entityMetamodel.getBytecodeEnhancementMetadata()
68-
.getLazyAttributesMetadata()
69-
.getLazyAttributeNames(),
7076
null
7177
) );
7278
}

0 commit comments

Comments
 (0)