Skip to content

Commit b752ad9

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 46a149d commit b752ad9

File tree

5 files changed

+100
-26
lines changed

5 files changed

+100
-26
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ private static void findAccessors(
12131213
getterMember = getter.getMethod();
12141214
}
12151215
else if ( getter instanceof GetterFieldImpl ) {
1216-
getterMember = getter.getMember();
1216+
getterMember = ((GetterFieldImpl) getter).getField();
12171217
}
12181218
else {
12191219
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
@@ -6,6 +6,9 @@
66
*/
77
package org.hibernate.property.access.internal;
88

9+
import jakarta.persistence.AccessType;
10+
import org.checkerframework.checker.nullness.qual.Nullable;
11+
import org.hibernate.property.access.spi.EnhancedGetterFieldImpl;
912
import org.hibernate.property.access.spi.EnhancedSetterImpl;
1013
import org.hibernate.property.access.spi.EnhancedSetterMethodImpl;
1114
import org.hibernate.property.access.spi.Getter;
@@ -19,9 +22,7 @@
1922
import java.lang.reflect.Field;
2023
import java.lang.reflect.Method;
2124

22-
import jakarta.persistence.AccessType;
23-
import org.checkerframework.checker.nullness.qual.Nullable;
24-
25+
import static org.hibernate.internal.util.ReflectHelper.findField;
2526
import static org.hibernate.internal.util.ReflectHelper.findSetterMethod;
2627
import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull;
2728
import static org.hibernate.property.access.internal.AccessStrategyHelper.fieldOrNull;
@@ -43,10 +44,12 @@ public PropertyAccessEnhancedImpl(
4344
PropertyAccessStrategy strategy,
4445
Class<?> containerJavaType,
4546
String propertyName,
46-
@Nullable AccessType getterAccessType) {
47+
@Nullable AccessType classAccessType) {
4748
this.strategy = strategy;
4849

49-
final AccessType propertyAccessType = resolveAccessType( getterAccessType, containerJavaType, propertyName );
50+
final AccessType propertyAccessType = classAccessType == null ?
51+
AccessStrategyHelper.getAccessType( containerJavaType, propertyName ) :
52+
classAccessType;
5053

5154
switch ( propertyAccessType ) {
5255
case FIELD: {
@@ -67,10 +70,8 @@ public PropertyAccessEnhancedImpl(
6770
"Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
6871
);
6972
}
70-
final Method setterMethod = findSetterMethod( containerJavaType, propertyName, getterMethod.getReturnType() );
71-
72-
this.getter = new GetterMethodImpl( containerJavaType, propertyName, getterMethod );
73-
this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod );
73+
this.getter = propertyGetter( classAccessType, containerJavaType, propertyName, getterMethod );
74+
this.setter = propertySetter( classAccessType, containerJavaType, propertyName, getterMethod.getReturnType() );
7475
break;
7576
}
7677
default: {
@@ -81,12 +82,31 @@ public PropertyAccessEnhancedImpl(
8182
}
8283
}
8384

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

92112
@Override

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,28 @@ public static PropertyAccessStrategyEnhancedImpl with(AccessType getterAccessTyp
2525
return STANDARD;
2626
}
2727

28-
return switch ( getterAccessType ) {
29-
case FIELD -> FIELD;
30-
case PROPERTY -> PROPERTY;
31-
};
28+
switch ( getterAccessType ) {
29+
case FIELD:
30+
return FIELD;
31+
case PROPERTY:
32+
return PROPERTY;
33+
default:
34+
return STANDARD;
35+
}
3236
}
3337

34-
private final @Nullable AccessType getterAccessType;
38+
private final @Nullable AccessType classAccessType;
3539

3640
public static PropertyAccessStrategyEnhancedImpl STANDARD = new PropertyAccessStrategyEnhancedImpl( null );
3741
public static PropertyAccessStrategyEnhancedImpl FIELD = new PropertyAccessStrategyEnhancedImpl( AccessType.FIELD );
3842
public static PropertyAccessStrategyEnhancedImpl PROPERTY = new PropertyAccessStrategyEnhancedImpl( AccessType.PROPERTY );
3943

40-
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType getterAccessType) {
41-
this.getterAccessType = getterAccessType;
44+
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType classAccessType) {
45+
this.classAccessType = classAccessType;
4246
}
4347

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

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
@@ -35,11 +35,14 @@ public class GetterFieldImpl implements Getter {
3535
private final @Nullable Method getterMethod;
3636

3737
public GetterFieldImpl(Class<?> containerClass, String propertyName, Field field) {
38+
this ( containerClass, propertyName, field, ReflectHelper.findGetterMethodForFieldAccess( field, propertyName ) );
39+
}
40+
41+
GetterFieldImpl(Class<?> containerClass, String propertyName, Field field, Method getterMethod) {
3842
this.containerClass = containerClass;
3943
this.propertyName = propertyName;
4044
this.field = field;
41-
42-
this.getterMethod = ReflectHelper.findGetterMethodForFieldAccess( field, propertyName );
45+
this.getterMethod = getterMethod;
4346
}
4447

4548
@Override
@@ -78,9 +81,13 @@ public Type getReturnType() {
7881
return field.getGenericType();
7982
}
8083

84+
public Field getField() {
85+
return field;
86+
}
87+
8188
@Override
8289
public Member getMember() {
83-
return field;
90+
return getField();
8491
}
8592

8693
@Override

0 commit comments

Comments
 (0)