HHH-9985 - remove hack based on exposed state and route all field access to enhanced methods, if present
This commit is contained in:
parent
ed185b9b48
commit
c622d39199
|
@ -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,
|
||||
|
|
|
@ -330,6 +330,7 @@ public class Property implements Serializable, MetaAttributable {
|
|||
: EntityMode.POJO;
|
||||
|
||||
return resolveServiceRegistry().getService( PropertyAccessStrategyResolver.class ).resolvePropertyAccessStrategy(
|
||||
clazz,
|
||||
accessName,
|
||||
entityMode
|
||||
);
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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() + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Class, String> 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<Class, String> 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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue