Skip to content

Commit 8a4bc4f

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 b0d8131 commit 8a4bc4f

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
@@ -1212,8 +1212,8 @@ private static void findAccessors(
12121212
if ( getter instanceof GetterMethodImpl ) {
12131213
getterMember = getter.getMethod();
12141214
}
1215-
else if ( getter instanceof GetterFieldImpl ) {
1216-
getterMember = getter.getMember();
1215+
else if ( getter instanceof GetterFieldImpl getterField ) {
1216+
getterMember = getterField.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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ public static PropertyAccessStrategyEnhancedImpl with(AccessType getterAccessTyp
3131
};
3232
}
3333

34-
private final @Nullable AccessType getterAccessType;
34+
private final @Nullable AccessType classAccessType;
3535

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

40-
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType getterAccessType) {
41-
this.getterAccessType = getterAccessType;
40+
public PropertyAccessStrategyEnhancedImpl(@Nullable AccessType classAccessType) {
41+
this.classAccessType = classAccessType;
4242
}
4343

4444
@Override
4545
public PropertyAccess buildPropertyAccess(Class<?> containerJavaType, final String propertyName, boolean setterRequired) {
46-
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName, getterAccessType );
46+
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName, classAccessType );
4747
}
4848
}
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
@@ -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)