diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index b42f817619..833b6aedc0 100755 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -15,7 +15,6 @@ import org.hibernate.ObjectDeletedException; import org.hibernate.StaleObjectStateException; import org.hibernate.WrongClassException; import org.hibernate.boot.registry.selector.spi.StrategySelector; -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader; import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.internal.Cascade; @@ -24,8 +23,6 @@ import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.CascadingActions; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; @@ -346,26 +343,15 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme } } - // for enhanced entities, copy over the dirty attributes and the lazy/loaded fields in the interceptor + // for enhanced entities, copy over the dirty attributes if ( entity instanceof SelfDirtinessTracker && target instanceof SelfDirtinessTracker ) { + // clear, because setting the embedded attributes dirties them + ( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes(); + for ( String fieldName : ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() ) { ( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( fieldName ); } } - if ( entity instanceof PersistentAttributeInterceptable - && target instanceof PersistentAttributeInterceptable - && ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor() != null - && ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor() != null ) { - - PersistentAttributeInterceptor entityInterceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); - PersistentAttributeInterceptor targetInterceptor = ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor(); - - if ( entityInterceptor instanceof LazyAttributeLoader && targetInterceptor instanceof LazyAttributeLoader ) { - for ( String fieldName : ( (LazyAttributeLoader) entityInterceptor ).getiInitializedFields() ) { - ( (LazyAttributeLoader) targetInterceptor ).setLoaded( fieldName ); - } - } - } } private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) { @@ -415,7 +401,6 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme final Object[] copiedValues = TypeHelper.replace( persister.getPropertyValues( entity ), persister.getPropertyValues( target ), - persister.getPropertyNames(), persister.getPropertyTypes(), source, target, @@ -453,7 +438,6 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme copiedValues = TypeHelper.replace( persister.getPropertyValues( entity ), persister.getPropertyValues( target ), - persister.getPropertyNames(), persister.getPropertyTypes(), source, target, diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 2e06e8bdcb..9699d974dd 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -330,6 +330,7 @@ public class Property implements Serializable, MetaAttributable { : EntityMode.POJO; return resolveServiceRegistry().getService( PropertyAccessStrategyResolver.class ).resolvePropertyAccessStrategy( + clazz, accessName, entityMode ); diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java new file mode 100644 index 0000000000..d8886cf7e1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java @@ -0,0 +1,152 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.property.access.internal; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.hibernate.PropertyNotFoundException; +import org.hibernate.bytecode.enhance.spi.EnhancerConstants; +import org.hibernate.internal.util.ReflectHelper; +import org.hibernate.property.access.spi.EnhancedGetterMethodImpl; +import org.hibernate.property.access.spi.EnhancedSetterMethodImpl; +import org.hibernate.property.access.spi.Getter; +import org.hibernate.property.access.spi.GetterFieldImpl; +import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.property.access.spi.PropertyAccessBuildingException; +import org.hibernate.property.access.spi.PropertyAccessStrategy; +import org.hibernate.property.access.spi.Setter; +import org.hibernate.property.access.spi.SetterFieldImpl; + +/** + * A PropertyAccess for byte code enhanced entities. Enhanced getter / setter methods ( if available ) are used for + * field access. Regular getter / setter methods are used for property access. In both cases, delegates calls to + * EnhancedMethodGetterImpl / EnhancedMethodGetterImpl. Based upon PropertyAccessMixedImpl. + * + * @author Steve Ebersole + * @author Luis Barreiro + */ +public class PropertyAccessEnhancedImpl implements PropertyAccess { + private final PropertyAccessStrategyEnhancedImpl strategy; + + private final Getter getter; + private final Setter setter; + + public PropertyAccessEnhancedImpl( + PropertyAccessStrategyEnhancedImpl strategy, + Class containerJavaType, + String propertyName) { + this.strategy = strategy; + + final Field field = fieldOrNull( containerJavaType, propertyName ); + final Method getterMethod = getterMethodOrNull( containerJavaType, propertyName ); + + final Class propertyJavaType; + + // need one of field or getterMethod to be non-null + if ( field == null && getterMethod == null ) { + String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]", + containerJavaType.getName(), + propertyName ); + throw new PropertyAccessBuildingException( msg ); + } + else if ( field != null ) { + propertyJavaType = field.getType(); + this.getter = resolveGetterForField( containerJavaType, propertyName, field ); + } + else { + propertyJavaType = getterMethod.getReturnType(); + this.getter = new EnhancedGetterMethodImpl( containerJavaType, propertyName, getterMethod ); + } + + final Method setterMethod = setterMethodOrNull( containerJavaType, propertyName, propertyJavaType ); + + // need one of field or setterMethod to be non-null + if ( field == null && setterMethod == null ) { + String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]", + containerJavaType.getName(), + propertyName ); + throw new PropertyAccessBuildingException( msg ); + } + else if ( field != null ) { + this.setter = resolveSetterForField( containerJavaType, propertyName, field ); + } + else { + this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod ); + } + } + + private static Field fieldOrNull(Class containerJavaType, String propertyName) { + try { + return ReflectHelper.findField( containerJavaType, propertyName ); + } + catch (PropertyNotFoundException e) { + return null; + } + } + + private static Method getterMethodOrNull(Class containerJavaType, String propertyName) { + try { + return ReflectHelper.findGetterMethod( containerJavaType, propertyName ); + } + catch (PropertyNotFoundException e) { + return null; + } + } + + private static Method setterMethodOrNull(Class containerJavaType, String propertyName, Class propertyJavaType) { + try { + return ReflectHelper.findSetterMethod( containerJavaType, propertyName, propertyJavaType ); + } + catch (PropertyNotFoundException e) { + return null; + } + } + + // + + private static Getter resolveGetterForField(Class containerClass, String propertyName, Field field) { + try { + String enhancedGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + propertyName; + Method enhancedGetter = containerClass.getDeclaredMethod( enhancedGetterName ); + enhancedGetter.setAccessible( true ); + return new EnhancedGetterMethodImpl( containerClass, propertyName, enhancedGetter ); + } + catch (NoSuchMethodException e) { + // enhancedGetter = null --- field not enhanced: fallback to reflection using the field + return new GetterFieldImpl( containerClass, propertyName, field ); + } + } + + private static Setter resolveSetterForField(Class containerClass, String propertyName, Field field) { + try { + String enhancedSetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + propertyName; + Method enhancedSetter = containerClass.getDeclaredMethod( enhancedSetterName, field.getType() ); + enhancedSetter.setAccessible( true ); + return new EnhancedSetterMethodImpl( containerClass, propertyName, enhancedSetter ); + } + catch (NoSuchMethodException e) { + // enhancedSetter = null --- field not enhanced: fallback to reflection using the field + return new SetterFieldImpl( containerClass, propertyName, field ); + } + } + + @Override + public PropertyAccessStrategy getPropertyAccessStrategy() { + return strategy; + } + + @Override + public Getter getGetter() { + return getter; + } + + @Override + public Setter getSetter() { + return setter; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessFieldImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessFieldImpl.java index 06aba35636..b717a70d67 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessFieldImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessFieldImpl.java @@ -22,8 +22,8 @@ import org.hibernate.property.access.spi.SetterFieldImpl; */ public class PropertyAccessFieldImpl implements PropertyAccess { private final PropertyAccessStrategyFieldImpl strategy; - private final GetterFieldImpl getter; - private final SetterFieldImpl setter; + private final Getter getter; + private final Setter setter; public PropertyAccessFieldImpl( PropertyAccessStrategyFieldImpl strategy, @@ -50,4 +50,5 @@ public class PropertyAccessFieldImpl implements PropertyAccess { public Setter getSetter() { return setter; } + } diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyEnhancedImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyEnhancedImpl.java new file mode 100644 index 0000000000..72f6fe8c6d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyEnhancedImpl.java @@ -0,0 +1,29 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.property.access.internal; + +import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.property.access.spi.PropertyAccessStrategy; + +/** + * Defines a strategy for accessing property values via a get/set pair, which may be nonpublic. This + * is the default (and recommended) strategy. + * + * @author Steve Ebersole + * @author Gavin King + */ +public class PropertyAccessStrategyEnhancedImpl implements PropertyAccessStrategy { + /** + * Singleton access + */ + public static final PropertyAccessStrategyEnhancedImpl INSTANCE = new PropertyAccessStrategyEnhancedImpl(); + + @Override + public PropertyAccess buildPropertyAccess(Class containerJavaType, final String propertyName) { + return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java index 43bd1de2c3..55341ada95 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java @@ -6,9 +6,12 @@ */ package org.hibernate.property.access.internal; +import java.lang.reflect.Method; + import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.boot.registry.selector.spi.StrategySelector; +import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.internal.util.StringHelper; import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies; import org.hibernate.property.access.spi.PropertyAccessStrategy; @@ -29,8 +32,14 @@ public class PropertyAccessStrategyResolverStandardImpl implements PropertyAcces @Override public PropertyAccessStrategy resolvePropertyAccessStrategy( + Class containerClass, String explicitAccessStrategyName, EntityMode entityMode) { + + if ( hasBytecodeEnhancedAttributes( containerClass ) ) { + return PropertyAccessStrategyEnhancedImpl.INSTANCE; + } + if ( StringHelper.isNotEmpty( explicitAccessStrategyName ) ) { return resolveExplicitlyNamedPropertyAccessStrategy( explicitAccessStrategyName ); } @@ -65,4 +74,15 @@ public class PropertyAccessStrategyResolverStandardImpl implements PropertyAcces } return strategySelectorService; } + + private boolean hasBytecodeEnhancedAttributes(Class containerClass) { + for ( Method m : containerClass.getDeclaredMethods() ) { + if ( m.getName().startsWith( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX ) || + m.getName().startsWith( EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX ) ) { + return true; + } + } + return false; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java new file mode 100644 index 0000000000..a88e25f56d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java @@ -0,0 +1,152 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.property.access.spi; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.hibernate.PropertyAccessException; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.CoreMessageLogger; + +import static org.hibernate.internal.CoreLogging.messageLogger; + +/** + * @author Steve Ebersole + */ +public class EnhancedGetterMethodImpl implements Getter { + private static final CoreMessageLogger LOG = messageLogger( EnhancedGetterMethodImpl.class ); + + private final Class containerClass; + private final String propertyName; + private final Method getterMethod; + + public EnhancedGetterMethodImpl(Class containerClass, String propertyName, Method getterMethod) { + this.containerClass = containerClass; + this.propertyName = propertyName; + this.getterMethod = getterMethod; + } + + private boolean isAttributeLoaded(Object owner) { + if ( owner instanceof PersistentAttributeInterceptable ) { + PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) owner ).$$_hibernate_getInterceptor(); + if ( interceptor != null && interceptor instanceof LazyAttributeLoader ) { + return ( (LazyAttributeLoader) interceptor ).isAttributeLoaded( propertyName ); + } + } + return true; + } + + @Override + public Object get(Object owner) { + try { + + // We don't want to trigger lazy loading of byte code enhanced attributes + if ( isAttributeLoaded( owner ) ) { + return getterMethod.invoke( owner ); + } + return null; + + } + catch (InvocationTargetException ite) { + throw new PropertyAccessException( + ite, + "Exception occurred inside", + false, + containerClass, + propertyName + ); + } + catch (IllegalAccessException iae) { + throw new PropertyAccessException( + iae, + "IllegalAccessException occurred while calling", + false, + containerClass, + propertyName + ); + //cannot occur + } + catch (IllegalArgumentException iae) { + LOG.illegalPropertyGetterArgument( containerClass.getName(), propertyName ); + throw new PropertyAccessException( + iae, + "IllegalArgumentException occurred calling", + false, + containerClass, + propertyName + ); + } + } + + @Override + public Object getForInsert(Object owner, Map mergeMap, SessionImplementor session) { + return get( owner ); + } + + @Override + public Class getReturnType() { + return getterMethod.getReturnType(); + } + + @Override + public Member getMember() { + return getterMethod; + } + + @Override + public String getMethodName() { + return getterMethod.getName(); + } + + @Override + public Method getMethod() { + return getterMethod; + } + + private Object writeReplace() throws ObjectStreamException { + return new SerialForm( containerClass, propertyName, getterMethod ); + } + + private static class SerialForm implements Serializable { + private final Class containerClass; + private final String propertyName; + + private final Class declaringClass; + private final String methodName; + + private SerialForm(Class containerClass, String propertyName, Method method) { + this.containerClass = containerClass; + this.propertyName = propertyName; + this.declaringClass = method.getDeclaringClass(); + this.methodName = method.getName(); + } + + private Object readResolve() { + return new EnhancedGetterMethodImpl( containerClass, propertyName, resolveMethod() ); + } + + @SuppressWarnings("unchecked") + private Method resolveMethod() { + try { + return declaringClass.getDeclaredMethod( methodName ); + } + catch (NoSuchMethodException e) { + throw new PropertyAccessSerializationException( + "Unable to resolve getter method on deserialization : " + declaringClass.getName() + "#" + methodName + ); + } + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java new file mode 100644 index 0000000000..2264d23e4d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java @@ -0,0 +1,168 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.property.access.spi; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.hibernate.PropertyAccessException; +import org.hibernate.PropertySetterAccessException; +import org.hibernate.engine.spi.SelfDirtinessTracker; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.CoreMessageLogger; + +import static org.hibernate.internal.CoreLogging.messageLogger; + +/** + * @author Steve Ebersole + */ +public class EnhancedSetterMethodImpl implements Setter { + private static final CoreMessageLogger LOG = messageLogger( EnhancedSetterMethodImpl.class ); + + private final Class containerClass; + private final String propertyName; + private final Method setterMethod; + + private final boolean isPrimitive; + + public EnhancedSetterMethodImpl(Class containerClass, String propertyName, Method setterMethod) { + this.containerClass = containerClass; + this.propertyName = propertyName; + this.setterMethod = setterMethod; + this.isPrimitive = setterMethod.getParameterTypes()[0].isPrimitive(); + } + + @Override + public void set(Object target, Object value, SessionFactoryImplementor factory) { + try { + + // for enhanced attribute, don't flag as dirty + if ( target instanceof SelfDirtinessTracker ) { + ( (SelfDirtinessTracker) target ).$$_hibernate_suspendDirtyTracking( true ); + setterMethod.invoke( target, value ); + ( (SelfDirtinessTracker) target ).$$_hibernate_suspendDirtyTracking( false ); + } + else { + setterMethod.invoke( target, value ); + } + + } + catch (NullPointerException npe) { + if ( value == null && isPrimitive ) { + throw new PropertyAccessException( + npe, + "Null value was assigned to a property of primitive type", + true, + containerClass, + propertyName + ); + } + else { + throw new PropertyAccessException( + npe, + "NullPointerException occurred while calling", + true, + containerClass, + propertyName + ); + } + } + catch (InvocationTargetException ite) { + throw new PropertyAccessException( + ite, + "Exception occurred inside", + true, + containerClass, + propertyName + ); + } + catch (IllegalAccessException iae) { + throw new PropertyAccessException( + iae, + "IllegalAccessException occurred while calling", + true, + containerClass, + propertyName + ); + //cannot occur + } + catch (IllegalArgumentException iae) { + if ( value == null && isPrimitive ) { + throw new PropertyAccessException( + iae, + "Null value was assigned to a property of primitive type", + true, + containerClass, + propertyName + ); + } + else { + final Class expectedType = setterMethod.getParameterTypes()[0]; + LOG.illegalPropertySetterArgument( containerClass.getName(), propertyName ); + LOG.expectedType( expectedType.getName(), value == null ? null : value.getClass().getName() ); + throw new PropertySetterAccessException( + iae, + containerClass, + propertyName, + expectedType, + target, + value + ); + } + } + } + + @Override + public String getMethodName() { + return setterMethod.getName(); + } + + @Override + public Method getMethod() { + return setterMethod; + } + + private Object writeReplace() throws ObjectStreamException { + return new SerialForm( containerClass, propertyName, setterMethod ); + } + + private static class SerialForm implements Serializable { + private final Class containerClass; + private final String propertyName; + + private final Class declaringClass; + private final String methodName; + private final Class argumentType; + + private SerialForm(Class containerClass, String propertyName, Method method) { + this.containerClass = containerClass; + this.propertyName = propertyName; + this.declaringClass = method.getDeclaringClass(); + this.methodName = method.getName(); + this.argumentType = method.getParameterTypes()[0]; + } + + private Object readResolve() { + return new EnhancedSetterMethodImpl( containerClass, propertyName, resolveMethod() ); + } + + @SuppressWarnings("unchecked") + private Method resolveMethod() { + try { + return declaringClass.getDeclaredMethod( methodName, argumentType ); + } + catch (NoSuchMethodException e) { + throw new PropertyAccessSerializationException( + "Unable to resolve setter method on deserialization : " + declaringClass.getName() + "#" + + methodName + "(" + argumentType.getName() + ")" + ); + } + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/PropertyAccessStrategyResolver.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/PropertyAccessStrategyResolver.java index 2189afd9cb..c2c7aa2add 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/PropertyAccessStrategyResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/PropertyAccessStrategyResolver.java @@ -20,10 +20,14 @@ public interface PropertyAccessStrategyResolver extends Service { /** * Resolve the PropertyAccessStrategy to use * + * @param containerClass The java class of the entity * @param explicitAccessStrategyName The access strategy name explicitly specified, if any. * @param entityMode The entity mode in effect for the property, used to interpret different default strategies. * * @return The resolved PropertyAccessStrategy */ - PropertyAccessStrategy resolvePropertyAccessStrategy(String explicitAccessStrategyName, EntityMode entityMode); + PropertyAccessStrategy resolvePropertyAccessStrategy( + Class containerClass, + String explicitAccessStrategyName, + EntityMode entityMode); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java index 93b8be7b55..7d7da18a1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java @@ -315,6 +315,7 @@ public final class PropertyFactory { mappingProperty.getPersistentClass().getServiceRegistry().getService( PropertyAccessStrategyResolver.class ); final PropertyAccessStrategy propertyAccessStrategy = propertyAccessStrategyResolver.resolvePropertyAccessStrategy( + mappingProperty.getClass(), mappingProperty.getPropertyAccessorName(), EntityMode.POJO ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java index e16901549b..b53ac07a3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java @@ -524,10 +524,9 @@ public class ComponentType extends AbstractType implements CompositeType, Proced Object[] values = TypeHelper.replace( getPropertyValues( original, entityMode ), getPropertyValues( result, entityMode ), - propertyNames, propertyTypes, session, - result, + owner, copyCache ); @@ -557,10 +556,9 @@ public class ComponentType extends AbstractType implements CompositeType, Proced Object[] values = TypeHelper.replace( getPropertyValues( original, entityMode ), getPropertyValues( result, entityMode ), - propertyNames, propertyTypes, session, - result, + owner, copyCache, foreignKeyDirection ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java index 2cf4b1d359..13050a8ded 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java @@ -10,8 +10,6 @@ import java.io.Serializable; import java.util.Map; import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer; -import org.hibernate.engine.spi.CompositeOwner; -import org.hibernate.engine.spi.CompositeTracker; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.tuple.NonIdentifierAttribute; @@ -149,7 +147,6 @@ public class TypeHelper { public static Object[] replace( final Object[] original, final Object[] target, - final String[] names, final Type[] types, final SessionImplementor session, final Object owner, @@ -179,11 +176,6 @@ public class TypeHelper { else { copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache ); } - - // for bytecode enhanced entities, set the composite tracking structure - if ( copied[i] instanceof CompositeTracker && owner instanceof CompositeOwner ) { - ( (CompositeTracker) copied[i] ).$$_hibernate_setOwner( names[i], (CompositeOwner) owner ); - } } return copied; } @@ -204,7 +196,6 @@ public class TypeHelper { public static Object[] replace( final Object[] original, final Object[] target, - final String[] names, final Type[] types, final SessionImplementor session, final Object owner, @@ -219,11 +210,6 @@ public class TypeHelper { else { copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection ); } - - // for bytecode enhanced entities, set the composite tracking structure - if ( copied[i] instanceof CompositeTracker && owner instanceof CompositeOwner ) { - ( (CompositeTracker) copied[i] ).$$_hibernate_setOwner( names[i], (CompositeOwner) owner ); - } } return copied; } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/ReflectionTools.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/ReflectionTools.java index fed2079789..82219da0b9 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/ReflectionTools.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/ReflectionTools.java @@ -37,9 +37,9 @@ public abstract class ReflectionTools { ConcurrentReferenceHashMap.ReferenceType.SOFT ); - private static PropertyAccessStrategy getAccessStrategy(ServiceRegistry serviceRegistry, String accessorType) { + private static PropertyAccessStrategy getAccessStrategy(Class cls, ServiceRegistry serviceRegistry, String accessorType) { return serviceRegistry.getService( PropertyAccessStrategyResolver.class ) - .resolvePropertyAccessStrategy( accessorType, null ); + .resolvePropertyAccessStrategy( cls, accessorType, null ); } public static Getter getGetter(Class cls, PropertyData propertyData, ServiceRegistry serviceRegistry) { @@ -50,7 +50,7 @@ public abstract class ReflectionTools { final Pair key = Pair.make( cls, propertyName ); Getter value = GETTER_CACHE.get( key ); if ( value == null ) { - value = getAccessStrategy( serviceRegistry, accessorType ).buildPropertyAccess( cls, propertyName ).getGetter(); + value = getAccessStrategy( cls, serviceRegistry, accessorType ).buildPropertyAccess( cls, propertyName ).getGetter(); // It's ok if two getters are generated concurrently GETTER_CACHE.put( key, value ); } @@ -66,7 +66,7 @@ public abstract class ReflectionTools { final Pair key = Pair.make( cls, propertyName ); Setter value = SETTER_CACHE.get( key ); if ( value == null ) { - value = getAccessStrategy( serviceRegistry, accessorType ).buildPropertyAccess( cls, propertyName ).getSetter(); + value = getAccessStrategy( cls, serviceRegistry, accessorType ).buildPropertyAccess( cls, propertyName ).getSetter(); // It's ok if two setters are generated concurrently SETTER_CACHE.put( key, value ); }