Skip to content

Commit 2d5f845

Browse files
committed
HHH-18928 Use enhanced field access even when defaulting to PROPERTY
This avoids problems with unnecessary initialization of lazy properties when using instrumented getter/setter methods internally.
1 parent f30dd6f commit 2d5f845

File tree

5 files changed

+91
-23
lines changed

5 files changed

+91
-23
lines changed

hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,8 +1199,8 @@ private static void findAccessors(
11991199
if ( getter instanceof GetterMethodImpl ) {
12001200
getterMember = getter.getMethod();
12011201
}
1202-
else if ( getter instanceof GetterFieldImpl ) {
1203-
getterMember = getter.getMember();
1202+
else if ( getter instanceof GetterFieldImpl getterField ) {
1203+
getterMember = getterField.getField();
12041204
}
12051205
else {
12061206
throw new InvalidPropertyAccessorException(

hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
*/
55
package org.hibernate.property.access.internal;
66

7+
import jakarta.persistence.AccessType;
8+
import org.checkerframework.checker.nullness.qual.Nullable;
9+
import org.hibernate.property.access.spi.EnhancedGetterFieldImpl;
710
import org.hibernate.property.access.spi.EnhancedSetterImpl;
811
import org.hibernate.property.access.spi.EnhancedSetterMethodImpl;
912
import org.hibernate.property.access.spi.Getter;
@@ -17,9 +20,7 @@
1720
import java.lang.reflect.Field;
1821
import java.lang.reflect.Method;
1922

20-
import jakarta.persistence.AccessType;
21-
import org.checkerframework.checker.nullness.qual.Nullable;
22-
23+
import static org.hibernate.internal.util.ReflectHelper.findField;
2324
import static org.hibernate.internal.util.ReflectHelper.findSetterMethod;
2425
import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull;
2526
import static org.hibernate.property.access.internal.AccessStrategyHelper.fieldOrNull;
@@ -41,10 +42,12 @@ public PropertyAccessEnhancedImpl(
4142
PropertyAccessStrategy strategy,
4243
Class<?> containerJavaType,
4344
String propertyName,
44-
@Nullable AccessType getterAccessType) {
45+
@Nullable AccessType classAccessType) {
4546
this.strategy = strategy;
4647

47-
final AccessType propertyAccessType = resolveAccessType( getterAccessType, containerJavaType, propertyName );
48+
final AccessType propertyAccessType = classAccessType == null ?
49+
AccessStrategyHelper.getAccessType( containerJavaType, propertyName ) :
50+
classAccessType;
4851

4952
switch ( propertyAccessType ) {
5053
case FIELD: {
@@ -65,10 +68,8 @@ public PropertyAccessEnhancedImpl(
6568
"Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
6669
);
6770
}
68-
final Method setterMethod = findSetterMethod( containerJavaType, propertyName, getterMethod.getReturnType() );
69-
70-
this.getter = new GetterMethodImpl( containerJavaType, propertyName, getterMethod );
71-
this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod );
71+
this.getter = propertyGetter( classAccessType, containerJavaType, propertyName, getterMethod );
72+
this.setter = propertySetter( classAccessType, containerJavaType, propertyName, getterMethod.getReturnType() );
7273
break;
7374
}
7475
default: {
@@ -79,12 +80,31 @@ public PropertyAccessEnhancedImpl(
7980
}
8081
}
8182

82-
private static AccessType resolveAccessType(@Nullable AccessType getterAccessType, Class<?> containerJavaType, String propertyName) {
83-
if ( getterAccessType != null ) {
84-
// this should indicate FIELD access
85-
return getterAccessType;
83+
private static Getter propertyGetter(@Nullable AccessType classAccessType, Class<?> containerJavaType, String propertyName, Method getterMethod) {
84+
if ( classAccessType != null ) {
85+
final AccessType explicitAccessType = AccessStrategyHelper.getAccessType( containerJavaType, propertyName );
86+
if ( explicitAccessType == AccessType.FIELD ) {
87+
// We need to default to FIELD unless we have an explicit AccessType to avoid unnecessary initializations
88+
final Field field = findField( containerJavaType, propertyName );
89+
return new EnhancedGetterFieldImpl( containerJavaType, propertyName, field, getterMethod );
90+
}
91+
}
92+
// when classAccessType is null know PROPERTY is the explicit access type
93+
return new GetterMethodImpl( containerJavaType, propertyName, getterMethod );
94+
}
95+
96+
private static Setter propertySetter(@Nullable AccessType classAccessType, Class<?> containerJavaType, String propertyName, Class<?> fieldType) {
97+
if ( classAccessType != null ) {
98+
final AccessType explicitAccessType = AccessStrategyHelper.getAccessType( containerJavaType, propertyName );
99+
if ( explicitAccessType == AccessType.FIELD ) {
100+
// We need to default to FIELD unless we have an explicit AccessType to avoid unnecessary initializations
101+
final Field field = findField( containerJavaType, propertyName );
102+
return new EnhancedSetterImpl( containerJavaType, propertyName, field );
103+
}
86104
}
87-
return AccessStrategyHelper.getAccessType( containerJavaType, propertyName );
105+
// when classAccessType is null know PROPERTY is the explicit access type
106+
final Method setterMethod = findSetterMethod( containerJavaType, propertyName, fieldType );
107+
return new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod );
88108
}
89109

90110
@Override

hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyEnhancedImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@ public static PropertyAccessStrategyEnhancedImpl with(AccessType getterAccessTyp
2929
};
3030
}
3131

32-
private final @Nullable AccessType getterAccessType;
32+
private final @Nullable AccessType classAccessType;
3333

3434
public static PropertyAccessStrategyEnhancedImpl STANDARD = new PropertyAccessStrategyEnhancedImpl( null );
3535
public static PropertyAccessStrategyEnhancedImpl FIELD = new PropertyAccessStrategyEnhancedImpl( AccessType.FIELD );
3636
public static PropertyAccessStrategyEnhancedImpl PROPERTY = new PropertyAccessStrategyEnhancedImpl( AccessType.PROPERTY );
3737

38-
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType getterAccessType) {
39-
this.getterAccessType = getterAccessType;
38+
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType classAccessType) {
39+
this.classAccessType = classAccessType;
4040
}
4141

4242
@Override
4343
public PropertyAccess buildPropertyAccess(Class<?> containerJavaType, final String propertyName, boolean setterRequired) {
44-
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName, getterAccessType );
44+
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName, classAccessType );
4545
}
4646
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.property.access.spi;
6+
7+
import org.checkerframework.checker.nullness.qual.NonNull;
8+
import org.hibernate.Internal;
9+
10+
import java.lang.reflect.Field;
11+
import java.lang.reflect.Member;
12+
import java.lang.reflect.Method;
13+
14+
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
15+
16+
/**
17+
* A specialized Getter implementation for handling getting values from
18+
* a bytecode-enhanced Class. The reason we need specialized handling
19+
* is to produce the correct {@link java.lang.reflect.Member} while
20+
* using the {@link Field} to access values and ensure correct functionality.
21+
*
22+
* @author Steve Ebersole
23+
* @author Luis Barreiro
24+
*/
25+
@Internal
26+
public class EnhancedGetterFieldImpl extends GetterFieldImpl {
27+
public EnhancedGetterFieldImpl(Class<?> containerClass, String propertyName, Field field, Method getterMethod) {
28+
super( containerClass, propertyName, field, getterMethod );
29+
assert getterMethod != null;
30+
}
31+
32+
@Override
33+
public @NonNull Method getMethod() {
34+
return castNonNull( super.getMethod() );
35+
}
36+
37+
@Override
38+
public Member getMember() {
39+
return getMethod();
40+
}
41+
}

hibernate-core/src/main/java/org/hibernate/property/access/spi/GetterFieldImpl.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ public class GetterFieldImpl implements Getter {
3333
private final @Nullable Method getterMethod;
3434

3535
public GetterFieldImpl(Class<?> containerClass, String propertyName, Field field) {
36+
this ( containerClass, propertyName, field, ReflectHelper.findGetterMethodForFieldAccess( field, propertyName ) );
37+
}
38+
39+
GetterFieldImpl(Class<?> containerClass, String propertyName, Field field, Method getterMethod) {
3640
this.containerClass = containerClass;
3741
this.propertyName = propertyName;
3842
this.field = field;
39-
40-
this.getterMethod = ReflectHelper.findGetterMethodForFieldAccess( field, propertyName );
43+
this.getterMethod = getterMethod;
4144
}
4245

4346
@Override
@@ -76,9 +79,13 @@ public Type getReturnType() {
7679
return field.getGenericType();
7780
}
7881

82+
public Field getField() {
83+
return field;
84+
}
85+
7986
@Override
8087
public Member getMember() {
81-
return field;
88+
return getField();
8289
}
8390

8491
@Override

0 commit comments

Comments
 (0)