Skip to content

Commit c622d39

Browse files
committed
HHH-9985 - remove hack based on exposed state and route all field access to enhanced methods, if present
1 parent ed185b9 commit c622d39

File tree

13 files changed

+541
-45
lines changed

13 files changed

+541
-45
lines changed

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.hibernate.StaleObjectStateException;
1616
import org.hibernate.WrongClassException;
1717
import org.hibernate.boot.registry.selector.spi.StrategySelector;
18-
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
1918
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
2019
import org.hibernate.engine.config.spi.ConfigurationService;
2120
import org.hibernate.engine.internal.Cascade;
@@ -24,8 +23,6 @@
2423
import org.hibernate.engine.spi.CascadingActions;
2524
import org.hibernate.engine.spi.EntityEntry;
2625
import org.hibernate.engine.spi.EntityKey;
27-
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
28-
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
2926
import org.hibernate.engine.spi.SelfDirtinessTracker;
3027
import org.hibernate.engine.spi.SessionFactoryImplementor;
3128
import org.hibernate.engine.spi.SessionImplementor;
@@ -346,26 +343,15 @@ private void markInterceptorDirty(final Object entity, final Object target, Enti
346343
}
347344
}
348345

349-
// for enhanced entities, copy over the dirty attributes and the lazy/loaded fields in the interceptor
346+
// for enhanced entities, copy over the dirty attributes
350347
if ( entity instanceof SelfDirtinessTracker && target instanceof SelfDirtinessTracker ) {
348+
// clear, because setting the embedded attributes dirties them
349+
( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes();
350+
351351
for ( String fieldName : ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() ) {
352352
( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( fieldName );
353353
}
354354
}
355-
if ( entity instanceof PersistentAttributeInterceptable
356-
&& target instanceof PersistentAttributeInterceptable
357-
&& ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor() != null
358-
&& ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor() != null ) {
359-
360-
PersistentAttributeInterceptor entityInterceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
361-
PersistentAttributeInterceptor targetInterceptor = ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor();
362-
363-
if ( entityInterceptor instanceof LazyAttributeLoader && targetInterceptor instanceof LazyAttributeLoader ) {
364-
for ( String fieldName : ( (LazyAttributeLoader) entityInterceptor ).getiInitializedFields() ) {
365-
( (LazyAttributeLoader) targetInterceptor ).setLoaded( fieldName );
366-
}
367-
}
368-
}
369355
}
370356

371357
private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) {
@@ -415,7 +401,6 @@ protected void copyValues(
415401
final Object[] copiedValues = TypeHelper.replace(
416402
persister.getPropertyValues( entity ),
417403
persister.getPropertyValues( target ),
418-
persister.getPropertyNames(),
419404
persister.getPropertyTypes(),
420405
source,
421406
target,
@@ -453,7 +438,6 @@ protected void copyValues(
453438
copiedValues = TypeHelper.replace(
454439
persister.getPropertyValues( entity ),
455440
persister.getPropertyValues( target ),
456-
persister.getPropertyNames(),
457441
persister.getPropertyTypes(),
458442
source,
459443
target,

hibernate-core/src/main/java/org/hibernate/mapping/Property.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ public PropertyAccessStrategy getPropertyAccessStrategy(Class clazz) throws Mapp
330330
: EntityMode.POJO;
331331

332332
return resolveServiceRegistry().getService( PropertyAccessStrategyResolver.class ).resolvePropertyAccessStrategy(
333+
clazz,
333334
accessName,
334335
entityMode
335336
);
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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.internal;
8+
9+
import java.lang.reflect.Field;
10+
import java.lang.reflect.Method;
11+
12+
import org.hibernate.PropertyNotFoundException;
13+
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
14+
import org.hibernate.internal.util.ReflectHelper;
15+
import org.hibernate.property.access.spi.EnhancedGetterMethodImpl;
16+
import org.hibernate.property.access.spi.EnhancedSetterMethodImpl;
17+
import org.hibernate.property.access.spi.Getter;
18+
import org.hibernate.property.access.spi.GetterFieldImpl;
19+
import org.hibernate.property.access.spi.PropertyAccess;
20+
import org.hibernate.property.access.spi.PropertyAccessBuildingException;
21+
import org.hibernate.property.access.spi.PropertyAccessStrategy;
22+
import org.hibernate.property.access.spi.Setter;
23+
import org.hibernate.property.access.spi.SetterFieldImpl;
24+
25+
/**
26+
* A PropertyAccess for byte code enhanced entities. Enhanced getter / setter methods ( if available ) are used for
27+
* field access. Regular getter / setter methods are used for property access. In both cases, delegates calls to
28+
* EnhancedMethodGetterImpl / EnhancedMethodGetterImpl. Based upon PropertyAccessMixedImpl.
29+
*
30+
* @author Steve Ebersole
31+
* @author Luis Barreiro
32+
*/
33+
public class PropertyAccessEnhancedImpl implements PropertyAccess {
34+
private final PropertyAccessStrategyEnhancedImpl strategy;
35+
36+
private final Getter getter;
37+
private final Setter setter;
38+
39+
public PropertyAccessEnhancedImpl(
40+
PropertyAccessStrategyEnhancedImpl strategy,
41+
Class containerJavaType,
42+
String propertyName) {
43+
this.strategy = strategy;
44+
45+
final Field field = fieldOrNull( containerJavaType, propertyName );
46+
final Method getterMethod = getterMethodOrNull( containerJavaType, propertyName );
47+
48+
final Class propertyJavaType;
49+
50+
// need one of field or getterMethod to be non-null
51+
if ( field == null && getterMethod == null ) {
52+
String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]",
53+
containerJavaType.getName(),
54+
propertyName );
55+
throw new PropertyAccessBuildingException( msg );
56+
}
57+
else if ( field != null ) {
58+
propertyJavaType = field.getType();
59+
this.getter = resolveGetterForField( containerJavaType, propertyName, field );
60+
}
61+
else {
62+
propertyJavaType = getterMethod.getReturnType();
63+
this.getter = new EnhancedGetterMethodImpl( containerJavaType, propertyName, getterMethod );
64+
}
65+
66+
final Method setterMethod = setterMethodOrNull( containerJavaType, propertyName, propertyJavaType );
67+
68+
// need one of field or setterMethod to be non-null
69+
if ( field == null && setterMethod == null ) {
70+
String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]",
71+
containerJavaType.getName(),
72+
propertyName );
73+
throw new PropertyAccessBuildingException( msg );
74+
}
75+
else if ( field != null ) {
76+
this.setter = resolveSetterForField( containerJavaType, propertyName, field );
77+
}
78+
else {
79+
this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod );
80+
}
81+
}
82+
83+
private static Field fieldOrNull(Class containerJavaType, String propertyName) {
84+
try {
85+
return ReflectHelper.findField( containerJavaType, propertyName );
86+
}
87+
catch (PropertyNotFoundException e) {
88+
return null;
89+
}
90+
}
91+
92+
private static Method getterMethodOrNull(Class containerJavaType, String propertyName) {
93+
try {
94+
return ReflectHelper.findGetterMethod( containerJavaType, propertyName );
95+
}
96+
catch (PropertyNotFoundException e) {
97+
return null;
98+
}
99+
}
100+
101+
private static Method setterMethodOrNull(Class containerJavaType, String propertyName, Class propertyJavaType) {
102+
try {
103+
return ReflectHelper.findSetterMethod( containerJavaType, propertyName, propertyJavaType );
104+
}
105+
catch (PropertyNotFoundException e) {
106+
return null;
107+
}
108+
}
109+
110+
//
111+
112+
private static Getter resolveGetterForField(Class<?> containerClass, String propertyName, Field field) {
113+
try {
114+
String enhancedGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + propertyName;
115+
Method enhancedGetter = containerClass.getDeclaredMethod( enhancedGetterName );
116+
enhancedGetter.setAccessible( true );
117+
return new EnhancedGetterMethodImpl( containerClass, propertyName, enhancedGetter );
118+
}
119+
catch (NoSuchMethodException e) {
120+
// enhancedGetter = null --- field not enhanced: fallback to reflection using the field
121+
return new GetterFieldImpl( containerClass, propertyName, field );
122+
}
123+
}
124+
125+
private static Setter resolveSetterForField(Class<?> containerClass, String propertyName, Field field) {
126+
try {
127+
String enhancedSetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + propertyName;
128+
Method enhancedSetter = containerClass.getDeclaredMethod( enhancedSetterName, field.getType() );
129+
enhancedSetter.setAccessible( true );
130+
return new EnhancedSetterMethodImpl( containerClass, propertyName, enhancedSetter );
131+
}
132+
catch (NoSuchMethodException e) {
133+
// enhancedSetter = null --- field not enhanced: fallback to reflection using the field
134+
return new SetterFieldImpl( containerClass, propertyName, field );
135+
}
136+
}
137+
138+
@Override
139+
public PropertyAccessStrategy getPropertyAccessStrategy() {
140+
return strategy;
141+
}
142+
143+
@Override
144+
public Getter getGetter() {
145+
return getter;
146+
}
147+
148+
@Override
149+
public Setter getSetter() {
150+
return setter;
151+
}
152+
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
*/
2323
public class PropertyAccessFieldImpl implements PropertyAccess {
2424
private final PropertyAccessStrategyFieldImpl strategy;
25-
private final GetterFieldImpl getter;
26-
private final SetterFieldImpl setter;
25+
private final Getter getter;
26+
private final Setter setter;
2727

2828
public PropertyAccessFieldImpl(
2929
PropertyAccessStrategyFieldImpl strategy,
@@ -50,4 +50,5 @@ public Getter getGetter() {
5050
public Setter getSetter() {
5151
return setter;
5252
}
53+
5354
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.internal;
8+
9+
import org.hibernate.property.access.spi.PropertyAccess;
10+
import org.hibernate.property.access.spi.PropertyAccessStrategy;
11+
12+
/**
13+
* Defines a strategy for accessing property values via a get/set pair, which may be nonpublic. This
14+
* is the default (and recommended) strategy.
15+
*
16+
* @author Steve Ebersole
17+
* @author Gavin King
18+
*/
19+
public class PropertyAccessStrategyEnhancedImpl implements PropertyAccessStrategy {
20+
/**
21+
* Singleton access
22+
*/
23+
public static final PropertyAccessStrategyEnhancedImpl INSTANCE = new PropertyAccessStrategyEnhancedImpl();
24+
25+
@Override
26+
public PropertyAccess buildPropertyAccess(Class containerJavaType, final String propertyName) {
27+
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName );
28+
}
29+
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
*/
77
package org.hibernate.property.access.internal;
88

9+
import java.lang.reflect.Method;
10+
911
import org.hibernate.EntityMode;
1012
import org.hibernate.HibernateException;
1113
import org.hibernate.boot.registry.selector.spi.StrategySelector;
14+
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
1215
import org.hibernate.internal.util.StringHelper;
1316
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
1417
import org.hibernate.property.access.spi.PropertyAccessStrategy;
@@ -29,8 +32,14 @@ public PropertyAccessStrategyResolverStandardImpl(ServiceRegistry serviceRegistr
2932

3033
@Override
3134
public PropertyAccessStrategy resolvePropertyAccessStrategy(
35+
Class containerClass,
3236
String explicitAccessStrategyName,
3337
EntityMode entityMode) {
38+
39+
if ( hasBytecodeEnhancedAttributes( containerClass ) ) {
40+
return PropertyAccessStrategyEnhancedImpl.INSTANCE;
41+
}
42+
3443
if ( StringHelper.isNotEmpty( explicitAccessStrategyName ) ) {
3544
return resolveExplicitlyNamedPropertyAccessStrategy( explicitAccessStrategyName );
3645
}
@@ -65,4 +74,15 @@ protected StrategySelector strategySelectorService() {
6574
}
6675
return strategySelectorService;
6776
}
77+
78+
private boolean hasBytecodeEnhancedAttributes(Class<?> containerClass) {
79+
for ( Method m : containerClass.getDeclaredMethods() ) {
80+
if ( m.getName().startsWith( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX ) ||
81+
m.getName().startsWith( EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX ) ) {
82+
return true;
83+
}
84+
}
85+
return false;
86+
}
87+
6888
}

0 commit comments

Comments
 (0)