HHH-16542 - Bad get/is handling with bytecode enhancement
This commit is contained in:
parent
c3f25c83c5
commit
da71d54833
|
@ -17,8 +17,6 @@ import java.lang.reflect.ParameterizedType;
|
|||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -32,6 +30,8 @@ import org.hibernate.type.BasicType;
|
|||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType;
|
||||
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
/**
|
||||
* Utility class for various reflection operations.
|
||||
*
|
||||
|
@ -41,10 +41,6 @@ import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType;
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ReflectHelper {
|
||||
|
||||
private static final Pattern JAVA_CONSTANT_PATTERN = Pattern.compile(
|
||||
"[a-z\\d]+\\.([A-Z]+[a-z\\d]+)+\\$?([A-Z]{1}[a-z\\d]+)*\\.[A-Z_\\$]+", Pattern.UNICODE_CHARACTER_CLASS);
|
||||
|
||||
public static final Class[] NO_PARAM_SIGNATURE = ArrayHelper.EMPTY_CLASS_ARRAY;
|
||||
public static final Object[] NO_PARAMS = ArrayHelper.EMPTY_OBJECT_ARRAY;
|
||||
|
||||
|
@ -516,7 +512,17 @@ public final class ReflectHelper {
|
|||
return getter;
|
||||
}
|
||||
|
||||
private static Method getGetterOrNull(Class containerClass, String propertyName) {
|
||||
/**
|
||||
* Find the method that can be used as the setter for this property.
|
||||
*
|
||||
* @param containerClass The Class which contains the property
|
||||
* @param propertyName The name of the property
|
||||
*
|
||||
* @return The getter method, or {@code null} if there is none.
|
||||
*
|
||||
* @throws MappingException If the {@code containerClass} has both a get- and an is- form.
|
||||
*/
|
||||
public static Method getGetterOrNull(Class containerClass, String propertyName) {
|
||||
if ( isRecord( containerClass ) ) {
|
||||
try {
|
||||
return containerClass.getMethod( propertyName, NO_PARAM_SIGNATURE );
|
||||
|
@ -525,6 +531,7 @@ public final class ReflectHelper {
|
|||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
for ( Method method : containerClass.getDeclaredMethods() ) {
|
||||
// if the method has parameters, skip it
|
||||
if ( method.getParameterCount() != 0 ) {
|
||||
|
@ -562,6 +569,8 @@ public final class ReflectHelper {
|
|||
final String stemName = methodName.substring( 2 );
|
||||
String decapitalizedStemName = Introspector.decapitalize( stemName );
|
||||
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
|
||||
// not sure that this can ever really happen given the handling of "get" above.
|
||||
// but be safe
|
||||
verifyNoGetVariantExists( containerClass, propertyName, method, stemName );
|
||||
return method;
|
||||
}
|
||||
|
@ -571,8 +580,8 @@ public final class ReflectHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static void verifyNoIsVariantExists(
|
||||
Class containerClass,
|
||||
public static void verifyNoIsVariantExists(
|
||||
Class<?> containerClass,
|
||||
String propertyName,
|
||||
Method getMethod,
|
||||
String stemName) {
|
||||
|
@ -589,7 +598,8 @@ public final class ReflectHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static void checkGetAndIsVariants(
|
||||
|
||||
public static void checkGetAndIsVariants(
|
||||
Class containerClass,
|
||||
String propertyName,
|
||||
Method getMethod,
|
||||
|
@ -611,7 +621,7 @@ public final class ReflectHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static void verifyNoGetVariantExists(
|
||||
public static void verifyNoGetVariantExists(
|
||||
Class containerClass,
|
||||
String propertyName,
|
||||
Method isMethod,
|
||||
|
|
|
@ -13,19 +13,19 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
import org.hibernate.property.access.spi.PropertyAccessSerializationException;
|
||||
|
||||
/**
|
||||
* Abstract serialization replacement for field based Getter and Setter impls.
|
||||
* Base Serializable form for field (used as Getter or Setter)
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractFieldSerialForm implements Serializable {
|
||||
private final Class declaringClass;
|
||||
private final Class<?> declaringClass;
|
||||
private final String fieldName;
|
||||
|
||||
protected AbstractFieldSerialForm(Field field) {
|
||||
this( field.getDeclaringClass(), field.getName() );
|
||||
}
|
||||
|
||||
protected AbstractFieldSerialForm(Class declaringClass, String fieldName) {
|
||||
protected AbstractFieldSerialForm(Class<?> declaringClass, String fieldName) {
|
||||
this.declaringClass = declaringClass;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.property.access.spi.PropertyAccessSerializationException;
|
||||
|
||||
/**
|
||||
* Base Serializable form for setter methods
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractSetterMethodSerialForm implements Serializable {
|
||||
private final Class<?> containerClass;
|
||||
private final String propertyName;
|
||||
|
||||
private final Class<?> declaringClass;
|
||||
private final String methodName;
|
||||
private final Class<?> argumentType;
|
||||
|
||||
public AbstractSetterMethodSerialForm(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];
|
||||
}
|
||||
|
||||
public Class<?> getContainerClass() {
|
||||
return containerClass;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public Class<?> getDeclaringClass() {
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public Class<?> getArgumentType() {
|
||||
return argumentType;
|
||||
}
|
||||
|
||||
protected Method resolveMethod() {
|
||||
try {
|
||||
final Method method = declaringClass.getDeclaredMethod( methodName, argumentType );
|
||||
ReflectHelper.ensureAccessibility( method );
|
||||
return method;
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new PropertyAccessSerializationException(
|
||||
"Unable to resolve setter method on deserialization : " + declaringClass.getName() + "#"
|
||||
+ methodName + "(" + argumentType.getName() + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* 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.beans.Introspector;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
import org.hibernate.engine.spi.CompositeTracker;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeOwner;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeTracker;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isCompositeTracker;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptableType;
|
||||
import static org.hibernate.internal.util.ReflectHelper.NO_PARAM_SIGNATURE;
|
||||
import static org.hibernate.internal.util.ReflectHelper.findField;
|
||||
import static org.hibernate.internal.util.ReflectHelper.isRecord;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AccessStrategyHelper {
|
||||
public static final int COMPOSITE_TRACKER_MASK = 1;
|
||||
public static final int COMPOSITE_OWNER = 2;
|
||||
public static final int PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK = 4;
|
||||
|
||||
public static Field fieldOrNull(Class<?> containerJavaType, String propertyName) {
|
||||
try {
|
||||
return findField( containerJavaType, propertyName );
|
||||
}
|
||||
catch (PropertyNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static AccessType getAccessType(Class<?> containerJavaType, String propertyName) {
|
||||
final Field field = fieldOrNull( containerJavaType, propertyName );
|
||||
final AccessType explicitAccessType = getExplicitAccessType( containerJavaType, propertyName, field );
|
||||
if ( explicitAccessType != null ) {
|
||||
return explicitAccessType;
|
||||
}
|
||||
|
||||
// No @Access on property or field; check to see if containerJavaType has an explicit @Access
|
||||
AccessType classAccessType = getAccessTypeOrNull( containerJavaType );
|
||||
if ( classAccessType != null ) {
|
||||
return classAccessType;
|
||||
}
|
||||
|
||||
// prefer using the field for getting if we can
|
||||
return field != null ? AccessType.FIELD : AccessType.PROPERTY;
|
||||
}
|
||||
|
||||
public static AccessType getExplicitAccessType(Class<?> containerClass, String propertyName, Field field) {
|
||||
if ( isRecord( containerClass ) ) {
|
||||
try {
|
||||
containerClass.getMethod( propertyName, NO_PARAM_SIGNATURE );
|
||||
return AccessType.PROPERTY;
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if ( field != null
|
||||
&& field.isAnnotationPresent( Access.class )
|
||||
&& !field.isAnnotationPresent( Transient.class )
|
||||
&& !Modifier.isStatic( field.getModifiers() ) ) {
|
||||
return AccessType.FIELD;
|
||||
}
|
||||
|
||||
for ( Method method : containerClass.getDeclaredMethods() ) {
|
||||
// if the method has parameters, skip it
|
||||
if ( method.getParameterCount() != 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the method is a "bridge", skip it
|
||||
if ( method.isBridge() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( method.isAnnotationPresent( Transient.class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( Modifier.isStatic( method.getModifiers() ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String methodName = method.getName();
|
||||
|
||||
// try "get"
|
||||
if ( methodName.startsWith( "get" ) ) {
|
||||
final String stemName = methodName.substring( 3 );
|
||||
final String decapitalizedStemName = Introspector.decapitalize( stemName );
|
||||
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
|
||||
if ( method.isAnnotationPresent( Access.class ) ) {
|
||||
return AccessType.PROPERTY;
|
||||
}
|
||||
else {
|
||||
checkIsMethodVariant( containerClass, propertyName, method, stemName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if not "get", then try "is"
|
||||
if ( methodName.startsWith( "is" ) ) {
|
||||
final String stemName = methodName.substring( 2 );
|
||||
String decapitalizedStemName = Introspector.decapitalize( stemName );
|
||||
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
|
||||
if ( method.isAnnotationPresent( Access.class ) ) {
|
||||
return AccessType.PROPERTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void checkIsMethodVariant(
|
||||
Class<?> containerClass,
|
||||
String propertyName,
|
||||
Method method,
|
||||
String stemName) {
|
||||
final Method isMethodVariant = findIsMethodVariant( containerClass, stemName );
|
||||
if ( isMethodVariant == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isMethodVariant.isAnnotationPresent( Access.class ) ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"In trying to locate getter for property [%s], Class [%s] defined " +
|
||||
"both a `get` [%s] and `is` [%s] variant",
|
||||
propertyName,
|
||||
containerClass.getName(),
|
||||
method.toString(),
|
||||
isMethodVariant.toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static Method findIsMethodVariant(Class<?> containerClass, String stemName) {
|
||||
// verify that the Class does not also define a method with the same stem name with 'is'
|
||||
try {
|
||||
final Method isMethod = containerClass.getDeclaredMethod( "is" + stemName );
|
||||
if ( !Modifier.isStatic( isMethod.getModifiers() ) && isMethod.getAnnotation( Transient.class ) == null ) {
|
||||
return isMethod;
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException ignore) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static AccessType getAccessTypeOrNull(AnnotatedElement element) {
|
||||
if ( element == null ) {
|
||||
return null;
|
||||
}
|
||||
Access elementAccess = element.getAnnotation( Access.class );
|
||||
return elementAccess == null ? null : elementAccess.value();
|
||||
}
|
||||
|
||||
public static int determineEnhancementState(Class<?> containerClass, Class<?> attributeType) {
|
||||
return ( CompositeOwner.class.isAssignableFrom( containerClass ) ? AccessStrategyHelper.COMPOSITE_OWNER : 0 )
|
||||
| ( CompositeTracker.class.isAssignableFrom( attributeType ) ? AccessStrategyHelper.COMPOSITE_TRACKER_MASK : 0 )
|
||||
| ( isPersistentAttributeInterceptableType( containerClass ) ? AccessStrategyHelper.PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK : 0 );
|
||||
}
|
||||
|
||||
public static void handleEnhancedInjection(Object target, Object value, int enhancementState, String propertyName) {
|
||||
// This sets the component relation for dirty tracking purposes
|
||||
if ( ( enhancementState & COMPOSITE_OWNER ) != 0
|
||||
&& ( ( enhancementState & COMPOSITE_TRACKER_MASK ) != 0
|
||||
&& value != null
|
||||
|| isCompositeTracker( value ) ) ) {
|
||||
asCompositeTracker( value ).$$_hibernate_setOwner( propertyName, asCompositeOwner( target ) );
|
||||
}
|
||||
|
||||
// This marks the attribute as initialized, so it doesn't get lazily loaded afterward
|
||||
if ( ( enhancementState & PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK ) != 0 ) {
|
||||
PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( target ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof BytecodeLazyAttributeInterceptor ) {
|
||||
( (BytecodeLazyAttributeInterceptor) interceptor ).attributeInitialized( propertyName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ public class ChainedPropertyAccessImpl implements PropertyAccess, Getter, Setter
|
|||
return owner;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
for ( int i = 0; i < propertyAccesses.length; i++ ) {
|
||||
|
|
|
@ -55,6 +55,7 @@ public class PropertyAccessCompositeUserTypeImpl implements PropertyAccess, Gett
|
|||
return strategy.compositeUserType.getPropertyValue( owner, propertyIndex );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
return get( owner );
|
||||
|
|
|
@ -67,6 +67,7 @@ public class PropertyAccessEmbeddedImpl implements PropertyAccess {
|
|||
return owner;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
return owner;
|
||||
|
|
|
@ -7,11 +7,24 @@
|
|||
package org.hibernate.property.access.internal;
|
||||
|
||||
import org.hibernate.property.access.spi.EnhancedSetterImpl;
|
||||
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.GetterMethodImpl;
|
||||
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.SetterMethodImpl;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jakarta.persistence.AccessType;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.findSetterMethod;
|
||||
import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull;
|
||||
import static org.hibernate.property.access.internal.AccessStrategyHelper.fieldOrNull;
|
||||
|
||||
/**
|
||||
* A {@link PropertyAccess} for byte code enhanced entities. Enhanced setter methods ( if available ) are used for
|
||||
|
@ -20,17 +33,77 @@ import java.lang.reflect.Field;
|
|||
* @author Steve Ebersole
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
public class PropertyAccessEnhancedImpl extends PropertyAccessMixedImpl {
|
||||
public class PropertyAccessEnhancedImpl implements PropertyAccess {
|
||||
private final PropertyAccessStrategy strategy;
|
||||
|
||||
private final Getter getter;
|
||||
private final Setter setter;
|
||||
|
||||
public PropertyAccessEnhancedImpl(
|
||||
PropertyAccessStrategy strategy,
|
||||
Class<?> containerJavaType,
|
||||
String propertyName) {
|
||||
super( strategy, containerJavaType, propertyName );
|
||||
String propertyName,
|
||||
AccessType getterAccessType) {
|
||||
this.strategy = strategy;
|
||||
|
||||
final AccessType propertyAccessType = resolveAccessType( getterAccessType, containerJavaType, propertyName );
|
||||
|
||||
switch ( propertyAccessType ) {
|
||||
case FIELD: {
|
||||
final Field field = fieldOrNull( containerJavaType, propertyName );
|
||||
if ( field == null ) {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Could not locate field for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
this.getter = new GetterFieldImpl( containerJavaType, propertyName, field );
|
||||
this.setter = new EnhancedSetterImpl( containerJavaType, propertyName, field );
|
||||
break;
|
||||
}
|
||||
case PROPERTY: {
|
||||
final Method getterMethod = getterMethodOrNull( containerJavaType, propertyName );
|
||||
if ( getterMethod == null ) {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
final Method setterMethod = findSetterMethod( containerJavaType, propertyName, getterMethod.getReturnType() );
|
||||
|
||||
this.getter = new GetterMethodImpl( containerJavaType, propertyName, getterMethod );
|
||||
this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Invalid access type " + propertyAccessType + " for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AccessType resolveAccessType(AccessType getterAccessType, Class<?> containerJavaType, String propertyName) {
|
||||
if ( getterAccessType != null ) {
|
||||
// this should indicate FIELD access
|
||||
return getterAccessType;
|
||||
}
|
||||
|
||||
// prefer using the field for getting if we can
|
||||
final Field field = AccessStrategyHelper.fieldOrNull( containerJavaType, propertyName );
|
||||
return field != null ? AccessType.FIELD : AccessType.PROPERTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Setter fieldSetter(Class<?> containerJavaType, String propertyName, Field field) {
|
||||
return new EnhancedSetterImpl( containerJavaType, propertyName, field );
|
||||
public PropertyAccessStrategy getPropertyAccessStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Getter getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Setter getSetter() {
|
||||
return setter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ public class PropertyAccessMapImpl implements PropertyAccess {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Object get(Object owner) {
|
||||
return ( (Map) owner ).get( propertyName );
|
||||
}
|
||||
|
|
|
@ -6,14 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.property.access.internal;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.GetterFieldImpl;
|
||||
import org.hibernate.property.access.spi.GetterMethodImpl;
|
||||
|
@ -24,8 +19,10 @@ import org.hibernate.property.access.spi.Setter;
|
|||
import org.hibernate.property.access.spi.SetterFieldImpl;
|
||||
import org.hibernate.property.access.spi.SetterMethodImpl;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull;
|
||||
import jakarta.persistence.AccessType;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.findSetterMethod;
|
||||
import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull;
|
||||
|
||||
/**
|
||||
* A {@link PropertyAccess} based on mix of getter/setter method and/or field.
|
||||
|
@ -38,20 +35,16 @@ public class PropertyAccessMixedImpl implements PropertyAccess {
|
|||
private final Getter getter;
|
||||
private final Setter setter;
|
||||
|
||||
public PropertyAccessMixedImpl(
|
||||
PropertyAccessStrategy strategy,
|
||||
Class<?> containerJavaType,
|
||||
String propertyName) {
|
||||
public PropertyAccessMixedImpl(PropertyAccessStrategy strategy, Class<?> containerJavaType, String propertyName) {
|
||||
this.strategy = strategy;
|
||||
|
||||
AccessType propertyAccessType = getAccessType( containerJavaType, propertyName );
|
||||
|
||||
final AccessType propertyAccessType = AccessStrategyHelper.getAccessType( containerJavaType, propertyName );
|
||||
switch ( propertyAccessType ) {
|
||||
case FIELD: {
|
||||
Field field = fieldOrNull( containerJavaType, propertyName );
|
||||
Field field = AccessStrategyHelper.fieldOrNull( containerJavaType, propertyName );
|
||||
if ( field == null ) {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Could not locate field for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
"Could not locate field for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
this.getter = fieldGetter( containerJavaType, propertyName, field );
|
||||
|
@ -62,7 +55,7 @@ public class PropertyAccessMixedImpl implements PropertyAccess {
|
|||
Method getterMethod = getterMethodOrNull( containerJavaType, propertyName );
|
||||
if ( getterMethod == null ) {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
"Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
Method setterMethod = findSetterMethod( containerJavaType, propertyName, getterMethod.getReturnType() );
|
||||
|
@ -73,47 +66,12 @@ public class PropertyAccessMixedImpl implements PropertyAccess {
|
|||
}
|
||||
default: {
|
||||
throw new PropertyAccessBuildingException(
|
||||
"Invalid access type " + propertyAccessType + " for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
"Invalid access type " + propertyAccessType + " for property named [" + containerJavaType.getName() + "#" + propertyName + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static Field fieldOrNull(Class<?> containerJavaType, String propertyName) {
|
||||
try {
|
||||
return ReflectHelper.findField( containerJavaType, propertyName );
|
||||
}
|
||||
catch (PropertyNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static AccessType getAccessType(Class<?> containerJavaType, String propertyName) {
|
||||
Field field = fieldOrNull( containerJavaType, propertyName );
|
||||
AccessType fieldAccessType = getAccessTypeOrNull( field );
|
||||
if ( fieldAccessType != null ) {
|
||||
return fieldAccessType;
|
||||
}
|
||||
AccessType methodAccessType = getAccessTypeOrNull( getterMethodOrNull( containerJavaType, propertyName ) );
|
||||
if ( methodAccessType != null ) {
|
||||
return methodAccessType;
|
||||
}
|
||||
// No @Access on property or field; check to see if containerJavaType has an explicit @Access
|
||||
AccessType classAccessType = getAccessTypeOrNull( containerJavaType );
|
||||
if ( classAccessType != null ) {
|
||||
return classAccessType;
|
||||
}
|
||||
return field != null ? AccessType.FIELD : AccessType.PROPERTY;
|
||||
}
|
||||
|
||||
private static AccessType getAccessTypeOrNull(AnnotatedElement element) {
|
||||
if ( element == null ) {
|
||||
return null;
|
||||
}
|
||||
Access elementAccess = element.getAnnotation( Access.class );
|
||||
return elementAccess == null ? null : elementAccess.value();
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
protected Getter fieldGetter(Class<?> containerJavaType, String propertyName, Field field) {
|
||||
|
|
|
@ -92,6 +92,7 @@ public class PropertyAccessStrategyBackRefImpl implements PropertyAccessStrategy
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
if ( session == null ) {
|
||||
return UNKNOWN;
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.property.access.internal;
|
||||
|
||||
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
||||
|
||||
import jakarta.persistence.AccessType;
|
||||
|
||||
/**
|
||||
* Defines a strategy for accessing property values via a get/set pair, which may be nonpublic. This
|
||||
* is the default (and recommended) strategy.
|
||||
|
@ -17,13 +20,24 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class PropertyAccessStrategyEnhancedImpl implements PropertyAccessStrategy {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final PropertyAccessStrategyEnhancedImpl INSTANCE = new PropertyAccessStrategyEnhancedImpl();
|
||||
public static PropertyAccessStrategyEnhancedImpl with(AccessType getterAccessType) {
|
||||
if ( getterAccessType == AccessType.FIELD ) {
|
||||
return FIELD;
|
||||
}
|
||||
return STANDARD;
|
||||
}
|
||||
|
||||
private final AccessType getterAccessType;
|
||||
|
||||
public static PropertyAccessStrategyEnhancedImpl STANDARD = new PropertyAccessStrategyEnhancedImpl( null );
|
||||
public static PropertyAccessStrategyEnhancedImpl FIELD = new PropertyAccessStrategyEnhancedImpl( AccessType.FIELD );
|
||||
|
||||
public PropertyAccessStrategyEnhancedImpl(AccessType getterAccessType) {
|
||||
this.getterAccessType = getterAccessType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyAccess buildPropertyAccess(Class<?> containerJavaType, final String propertyName, boolean setterRequired) {
|
||||
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName );
|
||||
return new PropertyAccessEnhancedImpl( this, containerJavaType, propertyName, getterAccessType );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public class PropertyAccessStrategyIndexBackRefImpl implements PropertyAccessStr
|
|||
return PropertyAccessStrategyBackRefImpl.UNKNOWN;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
if ( session == null ) {
|
||||
|
|
|
@ -67,6 +67,7 @@ public class PropertyAccessStrategyNoopImpl implements PropertyAccessStrategy {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
|||
import org.hibernate.property.access.spi.PropertyAccessStrategyResolver;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import jakarta.persistence.AccessType;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedType;
|
||||
|
||||
/**
|
||||
|
@ -40,8 +42,10 @@ public class PropertyAccessStrategyResolverStandardImpl implements PropertyAcces
|
|||
|| BuiltInPropertyAccessStrategies.MIXED.getExternalName().equals( explicitAccessStrategyName ) ) {
|
||||
//type-cache-pollution agent: it's crucial to use the ManagedTypeHelper rather than attempting a direct cast
|
||||
if ( isManagedType( containerClass ) ) {
|
||||
// PROPERTY (BASIC) and MIXED are not valid for bytecode enhanced entities...
|
||||
return PropertyAccessStrategyEnhancedImpl.INSTANCE;
|
||||
if ( BuiltInPropertyAccessStrategies.FIELD.getExternalName().equals( explicitAccessStrategyName ) ) {
|
||||
return PropertyAccessStrategyEnhancedImpl.FIELD;
|
||||
}
|
||||
return PropertyAccessStrategyEnhancedImpl.STANDARD;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,18 +9,11 @@ package org.hibernate.property.access.spi;
|
|||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
import org.hibernate.engine.spi.CompositeTracker;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
||||
import org.hibernate.property.access.internal.AccessStrategyHelper;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeOwner;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeTracker;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isCompositeTracker;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptableType;
|
||||
import static org.hibernate.property.access.internal.AccessStrategyHelper.determineEnhancementState;
|
||||
|
||||
/**
|
||||
* A specialized Setter implementation for handling setting values into
|
||||
|
@ -31,39 +24,21 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttrib
|
|||
* @author Steve Ebersole
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@Internal
|
||||
public class EnhancedSetterImpl extends SetterFieldImpl {
|
||||
|
||||
private static final int COMPOSITE_TRACKER_MASK = 1;
|
||||
private static final int COMPOSITE_OWNER = 2;
|
||||
private static final int PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK = 4;
|
||||
|
||||
private final String propertyName;
|
||||
private final int enhancementState;
|
||||
|
||||
public EnhancedSetterImpl(Class<?> containerClass, String propertyName, Field field) {
|
||||
super( containerClass, propertyName, field );
|
||||
this.propertyName = propertyName;
|
||||
this.enhancementState = ( CompositeOwner.class.isAssignableFrom( containerClass ) ? COMPOSITE_OWNER : 0 )
|
||||
| ( CompositeTracker.class.isAssignableFrom( field.getType() ) ? COMPOSITE_TRACKER_MASK : 0 )
|
||||
| ( isPersistentAttributeInterceptableType( containerClass ) ? PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK : 0 );
|
||||
this.enhancementState = determineEnhancementState( containerClass, field.getType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object target, Object value) {
|
||||
super.set( target, value );
|
||||
|
||||
// This sets the component relation for dirty tracking purposes
|
||||
if ( ( enhancementState & COMPOSITE_OWNER ) != 0 && ( ( enhancementState & COMPOSITE_TRACKER_MASK ) != 0 && value != null || isCompositeTracker( value ) ) ) {
|
||||
asCompositeTracker( value ).$$_hibernate_setOwner( propertyName, asCompositeOwner( target ) );
|
||||
}
|
||||
|
||||
// This marks the attribute as initialized, so it doesn't get lazily loaded afterwards
|
||||
if ( ( enhancementState & PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK ) != 0 ) {
|
||||
PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( target ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof BytecodeLazyAttributeInterceptor ) {
|
||||
( (BytecodeLazyAttributeInterceptor) interceptor ).attributeInitialized( propertyName );
|
||||
}
|
||||
}
|
||||
AccessStrategyHelper.handleEnhancedInjection( target, value, enhancementState, propertyName );
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,13 +49,12 @@ public class EnhancedSetterImpl extends SetterFieldImpl {
|
|||
return new SerialForm( getContainerClass(), propertyName, getField() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class SerialForm extends AbstractFieldSerialForm implements Serializable {
|
||||
private final Class containerClass;
|
||||
private final Class<?> containerClass;
|
||||
private final String propertyName;
|
||||
|
||||
|
||||
private SerialForm(Class containerClass, String propertyName, Field field) {
|
||||
private SerialForm(Class<?> containerClass, String propertyName, Field field) {
|
||||
super( field );
|
||||
this.containerClass = containerClass;
|
||||
this.propertyName = propertyName;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.property.access.internal.AbstractSetterMethodSerialForm;
|
||||
import org.hibernate.property.access.internal.AccessStrategyHelper;
|
||||
|
||||
import static org.hibernate.property.access.internal.AccessStrategyHelper.determineEnhancementState;
|
||||
|
||||
/**
|
||||
* A specialized Setter implementation for handling setting values into a bytecode-enhanced Class
|
||||
* using a setter method. The reason we need specialized handling is to render the fact that we
|
||||
* need to account for certain enhancement features during the setting process.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@Internal
|
||||
public class EnhancedSetterMethodImpl extends SetterMethodImpl {
|
||||
private final String propertyName;
|
||||
private final int enhancementState;
|
||||
|
||||
public EnhancedSetterMethodImpl(Class<?> containerClass, String propertyName, Method setterMethod) {
|
||||
super( containerClass, propertyName, setterMethod );
|
||||
this.propertyName = propertyName;
|
||||
this.enhancementState = determineEnhancementState( containerClass, setterMethod.getReturnType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object target, Object value) {
|
||||
super.set( target, value );
|
||||
|
||||
AccessStrategyHelper.handleEnhancedInjection( target, value, enhancementState, propertyName );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// serialization
|
||||
|
||||
private Object writeReplace() {
|
||||
return new SerialForm( getContainerClass(), propertyName, getMethod() );
|
||||
}
|
||||
|
||||
private static class SerialForm extends AbstractSetterMethodSerialForm implements Serializable {
|
||||
private SerialForm(Class<?> containerClass, String propertyName, Method method) {
|
||||
super( containerClass, propertyName, method );
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return new EnhancedSetterMethodImpl( getContainerClass(), getPropertyName(), resolveMethod() );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import java.lang.reflect.Type;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
||||
|
@ -24,6 +25,7 @@ import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class GetterFieldImpl implements Getter {
|
||||
private final Class<?> containerClass;
|
||||
private final String propertyName;
|
||||
|
@ -58,6 +60,7 @@ public class GetterFieldImpl implements Getter {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
return get( owner );
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.lang.reflect.Method;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.PropertyAccessException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
@ -25,6 +26,7 @@ import static org.hibernate.internal.CoreLogging.messageLogger;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class GetterMethodImpl implements Getter {
|
||||
private static final CoreMessageLogger LOG = messageLogger( GetterMethodImpl.class );
|
||||
|
||||
|
@ -74,6 +76,7 @@ public class GetterMethodImpl implements Getter {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object getForInsert(Object owner, Map mergeMap, SharedSessionContractImplementor session) {
|
||||
return get( owner );
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.PropertyAccessException;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
||||
|
@ -22,6 +23,7 @@ import org.hibernate.proxy.LazyInitializer;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class SetterFieldImpl implements Setter {
|
||||
private final Class<?> containerClass;
|
||||
private final String propertyName;
|
||||
|
@ -73,9 +75,12 @@ public class SetterFieldImpl implements Setter {
|
|||
if ( lazyInitializer != null ) {
|
||||
valueType = lazyInitializer.getEntityName();
|
||||
}
|
||||
else {
|
||||
else if ( value != null ) {
|
||||
valueType = value.getClass().getTypeName();
|
||||
}
|
||||
else {
|
||||
valueType = "<unknown>";
|
||||
}
|
||||
throw new PropertyAccessException(
|
||||
e,
|
||||
String.format(
|
||||
|
|
|
@ -10,16 +10,18 @@ import java.io.Serializable;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.PropertyAccessException;
|
||||
import org.hibernate.PropertySetterAccessException;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.property.access.internal.AbstractSetterMethodSerialForm;
|
||||
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class SetterMethodImpl implements Setter {
|
||||
private static final CoreMessageLogger LOG = messageLogger( SetterMethodImpl.class );
|
||||
|
||||
|
@ -107,6 +109,10 @@ public class SetterMethodImpl implements Setter {
|
|||
}
|
||||
}
|
||||
|
||||
public Class<?> getContainerClass() {
|
||||
return containerClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
return setterMethod.getName();
|
||||
|
@ -121,38 +127,13 @@ public class SetterMethodImpl implements Setter {
|
|||
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 static class SerialForm extends AbstractSetterMethodSerialForm implements Serializable {
|
||||
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];
|
||||
super( containerClass, propertyName, method );
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return new SetterMethodImpl( containerClass, propertyName, resolveMethod() );
|
||||
}
|
||||
|
||||
private Method resolveMethod() {
|
||||
try {
|
||||
final Method method = declaringClass.getDeclaredMethod( methodName, argumentType );
|
||||
ReflectHelper.ensureAccessibility( method );
|
||||
return method;
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new PropertyAccessSerializationException(
|
||||
"Unable to resolve setter method on deserialization : " + declaringClass.getName() + "#"
|
||||
+ methodName + "(" + argumentType.getName() + ")"
|
||||
);
|
||||
}
|
||||
return new SetterMethodImpl( getContainerClass(), getPropertyName(), resolveMethod() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.orm.test.property;
|
||||
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(annotatedClasses = FieldMappingWithGetterAndIsTest.Tester.class)
|
||||
@SessionFactory
|
||||
public class FieldMappingWithGetterAndIsTest {
|
||||
@Test
|
||||
public void testResolution(DomainModelScope modelScope, SessionFactoryScope factoryScope) {
|
||||
final PersistentClass entityBinding = modelScope.getEntityBinding( Tester.class );
|
||||
factoryScope.getCollectingStatementInspector();
|
||||
}
|
||||
|
||||
@Entity(name="Tester")
|
||||
@Table(name="Tester")
|
||||
public static class Tester {
|
||||
@Id
|
||||
private Integer id;
|
||||
@Basic
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isName() {
|
||||
return name != null;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.orm.test.property;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( inlineDirtyChecking = true, lazyLoading = true )
|
||||
public class FieldMappingWithGetterAndIsTest2 extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Tester.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolution() {
|
||||
sessionFactory();
|
||||
}
|
||||
|
||||
@Entity(name="Tester")
|
||||
@Table(name="Tester")
|
||||
public static class Tester {
|
||||
@Id
|
||||
private Integer id;
|
||||
@Basic
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isName() {
|
||||
return name != null;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue