DATACMNS-243 - Allow dedicated control over the access type for properties.

Introduced @AccessType annotation to allow user to control the way property values are accessed. The default is field access. Improved the property detection mechanism to also inspect all PropertyDescriptors not backed by a field and add them if property access is defined for the property or type. We also keep property accessors for interfaces as they strongly indicate property access to be used (as they cannot be field backed by definition).

The BeanWrapper doesn't take a useFieldAccess attribute anymore as the access type is solely derived from the given PersistentProperty now. AnnotationBasedPersistentProperty now also rejects properties with the very same annotation both on the field and on an accessor.
This commit is contained in:
Oliver Gierke
2013-03-25 16:39:52 +01:00
committed by Oliver Gierke
parent 4c5012f637
commit 4c6afc5c30
12 changed files with 458 additions and 165 deletions

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to define how Spring Data shall access values of persistent properties. Can either be {@link Type#FIELD}
* or {@link Type#PROPERTY}. Default is field access.
*
* @author Oliver Gierke
*/
@Documented
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, })
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessType {
/**
* The access type to be used.
*
* @return
*/
Type value();
enum Type {
FIELD, PROPERTY;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package org.springframework.data.mapping;
import java.lang.annotation.Annotation;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.util.TypeInformation;
@@ -150,4 +152,12 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
void doWithAssociations(AssociationHandler<P> handler);
void doWithAssociations(SimpleAssociationHandler handler);
/**
* Looks up the annotation of the given type on the {@link PersistentEntity}.
*
* @param annotationType must not be {@literal null}.
* @return
*/
<A extends Annotation> A findAnnotation(Class<A> annotationType);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,11 @@ import org.springframework.data.util.TypeInformation;
*/
public interface PersistentProperty<P extends PersistentProperty<P>> {
/**
* Returns the {@link PersistentEntity} owning the current {@link PersistentProperty}.
*
* @return
*/
PersistentEntity<?, P> getOwner();
/**
@@ -192,6 +197,15 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
*/
<A extends Annotation> A findAnnotation(Class<A> annotationType);
/**
* Looks up the annotation of the given type on the property and the owning type if no annotation can be found on it.
* Usefull to lookup annotations that can be configured on the type but overridden on an individual property.
*
* @param annotationType must not be {@literal null}.
* @return
*/
<A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType);
/**
* Returns whether the {@link PersistentProperty} has an annotation of the given type.
*
@@ -199,4 +213,12 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
* @return whether the {@link PersistentProperty} has an annotation of the given type.
*/
boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/**
* Returns whether property access shall be used for reading the property value. This means it will use the getter
* instead of field access.
*
* @return
*/
boolean usePropertyAccess();
}

View File

@@ -291,8 +291,10 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
try {
ReflectionUtils.doWithFields(type, new PersistentPropertyCreator(entity, descriptors),
PersistentFieldFilter.INSTANCE);
PersistentPropertyCreator persistentPropertyCreator = new PersistentPropertyCreator(entity, descriptors);
ReflectionUtils.doWithFields(type, persistentPropertyCreator, PersistentPropertyFilter.INSTANCE);
persistentPropertyCreator.addPropertiesForRemainingDescriptors();
entity.verify();
} catch (MappingException e) {
@@ -394,30 +396,66 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
private final E entity;
private final Map<String, PropertyDescriptor> descriptors;
private final Map<String, PropertyDescriptor> remainingDescriptors;
/**
* Creates a new {@link PersistentPropertyCreator} for the given {@link PersistentEntity} and
* {@link PropertyDescriptor}s.
*
* @param entity
* @param descriptors
* @param entity must not be {@literal null}.
* @param descriptors must not be {@literal null}.
*/
private PersistentPropertyCreator(E entity, Map<String, PropertyDescriptor> descriptors) {
Assert.notNull(entity, "PersistentEntity must not be null!");
Assert.notNull(descriptors, "PropertyDescriptors must not be null!");
this.entity = entity;
this.descriptors = descriptors;
this.remainingDescriptors = new HashMap<String, PropertyDescriptor>(descriptors);
}
/*
* (non-Javadoc)
* @see org.springframework.util.ReflectionUtils.FieldCallback#doWith(java.lang.reflect.Field)
*/
public void doWith(Field field) {
PropertyDescriptor descriptor = descriptors.get(field.getName());
String fieldName = field.getName();
ReflectionUtils.makeAccessible(field);
createAndRegisterProperty(field, descriptors.get(fieldName));
this.remainingDescriptors.remove(fieldName);
}
/**
* Adds {@link PersistentProperty} instances for all suitable {@link PropertyDescriptor}s without a backing
* {@link Field}.
*
* @see PersistentPropertyFilter
*/
public void addPropertiesForRemainingDescriptors() {
for (PropertyDescriptor descriptor : remainingDescriptors.values()) {
if (PersistentPropertyFilter.INSTANCE.matches(descriptor)) {
createAndRegisterProperty(null, descriptor);
}
}
}
private void createAndRegisterProperty(Field field, PropertyDescriptor descriptor) {
P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder);
if (property.isTransient()) {
return;
}
if (field == null && !property.usePropertyAccess()) {
return;
}
entity.addPersistentProperty(property);
if (property.isAssociation()) {
@@ -439,25 +477,25 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
}
/**
* {@link FieldFilter} rejecting static fields as well as artifically introduced ones. See
* {@link PersistentFieldFilter#UNMAPPED_FIELDS} for details.
* Filter rejecting static fields as well as artifically introduced ones. See
* {@link PersistentPropertyFilter#UNMAPPED_PROPERTIES} for details.
*
* @author Oliver Gierke
*/
private static enum PersistentFieldFilter implements FieldFilter {
static enum PersistentPropertyFilter implements FieldFilter {
INSTANCE;
private static final Iterable<FieldMatch> UNMAPPED_FIELDS;
private static final Iterable<PropertyMatch> UNMAPPED_PROPERTIES;
static {
Set<FieldMatch> matches = new HashSet<FieldMatch>();
matches.add(new FieldMatch("class", null));
matches.add(new FieldMatch("this\\$.*", null));
matches.add(new FieldMatch("metaClass", "groovy.lang.MetaClass"));
Set<PropertyMatch> matches = new HashSet<PropertyMatch>();
matches.add(new PropertyMatch("class", null));
matches.add(new PropertyMatch("this\\$.*", null));
matches.add(new PropertyMatch("metaClass", "groovy.lang.MetaClass"));
UNMAPPED_FIELDS = Collections.unmodifiableCollection(matches);
UNMAPPED_PROPERTIES = Collections.unmodifiableCollection(matches);
}
/*
@@ -470,59 +508,82 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
return false;
}
for (FieldMatch candidate : UNMAPPED_FIELDS) {
if (candidate.matches(field)) {
for (PropertyMatch candidate : UNMAPPED_PROPERTIES) {
if (candidate.matches(field.getName(), field.getType())) {
return false;
}
}
return true;
}
}
/**
* Value object to help defining field eclusion based on name patterns and types.
*
* @since 1.4
* @author Oliver Gierke
*/
static class FieldMatch {
private final String namePattern;
private final String typeName;
/**
* Creates a new {@link FieldMatch} for the given name pattern and type name. At least one of the paramters must not
* be {@literal null}.
* Returns whether the given {@link PropertyDescriptor} is one to create a {@link PersistentProperty} for.
*
* @param namePattern a regex pattern to match field names, can be {@literal null}.
* @param typeName the name of the type to exclude, can be {@literal null}.
*/
public FieldMatch(String namePattern, String typeName) {
Assert.isTrue(!(namePattern == null && typeName == null), "Either name patter or type name must be given!");
this.namePattern = namePattern;
this.typeName = typeName;
}
/**
* Returns whether the given {@link Field} matches the defined {@link FieldMatch}.
*
* @param field must not be {@literal null}.
* @param descriptor must not be {@literal null}.
* @return
*/
public boolean matches(Field field) {
public boolean matches(PropertyDescriptor descriptor) {
if (namePattern != null && !field.getName().matches(namePattern)) {
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
if (descriptor.getReadMethod() == null && descriptor.getWriteMethod() == null) {
return false;
}
if (typeName != null && !field.getType().getName().equals(typeName)) {
return false;
for (PropertyMatch candidate : UNMAPPED_PROPERTIES) {
if (candidate.matches(descriptor.getName(), descriptor.getPropertyType())) {
return false;
}
}
return true;
}
/**
* Value object to help defining property exclusion based on name patterns and types.
*
* @since 1.4
* @author Oliver Gierke
*/
static class PropertyMatch {
private final String namePattern;
private final String typeName;
/**
* Creates a new {@link PropertyMatch} for the given name pattern and type name. At least one of the paramters
* must not be {@literal null}.
*
* @param namePattern a regex pattern to match field names, can be {@literal null}.
* @param typeName the name of the type to exclude, can be {@literal null}.
*/
public PropertyMatch(String namePattern, String typeName) {
Assert.isTrue(!(namePattern == null && typeName == null), "Either name patter or type name must be given!");
this.namePattern = namePattern;
this.typeName = typeName;
}
/**
* Returns whether the given {@link Field} matches the defined {@link PropertyMatch}.
*
* @param field must not be {@literal null}.
* @return
*/
public boolean matches(String name, Class<?> type) {
if (namePattern != null && !name.matches(namePattern)) {
return false;
}
if (typeName != null && !type.getName().equals(typeName)) {
return false;
}
return true;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,19 +16,20 @@
package org.springframework.data.mapping.model;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.Reference;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* Simple impementation of {@link PersistentProperty}.
@@ -38,6 +39,12 @@ import org.springframework.util.Assert;
*/
public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>> implements PersistentProperty<P> {
private static final Field CAUSE_FIELD;
static {
CAUSE_FIELD = ReflectionUtils.findField(Throwable.class, "cause");
}
protected final String name;
protected final PropertyDescriptor propertyDescriptor;
protected final TypeInformation<?> information;
@@ -50,12 +57,11 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner,
SimpleTypeHolder simpleTypeHolder) {
Assert.notNull(field);
Assert.notNull(simpleTypeHolder);
Assert.notNull(owner);
this.name = field.getName();
this.rawType = field.getType();
this.name = field == null ? propertyDescriptor.getName() : field.getName();
this.rawType = field == null ? propertyDescriptor.getPropertyType() : field.getType();
this.information = owner.getTypeInformation().getProperty(this.name);
this.propertyDescriptor = propertyDescriptor;
this.field = field;
@@ -113,18 +119,15 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
public Iterable<? extends TypeInformation<?>> getPersistentEntityType() {
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
TypeInformation<?> type = getTypeInformation();
if (isEntity()) {
result.add(type);
}
if (type.isCollectionLike() || isMap()) {
TypeInformation<?> nestedType = getTypeInformationIfNotSimpleType(getTypeInformation().getActualType());
if (nestedType != null) {
result.add(nestedType);
}
} else {
result.add(type);
}
return result;
@@ -209,16 +212,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
* @see org.springframework.data.mapping.PersistentProperty#isAssociation()
*/
public boolean isAssociation() {
if (field.isAnnotationPresent(Reference.class)) {
return true;
}
for (Annotation annotation : field.getDeclaredAnnotations()) {
if (annotation.annotationType().isAnnotationPresent(Reference.class)) {
return true;
}
}
return false;
return field == null ? false : AnnotationUtils.getAnnotation(field, Reference.class) != null;
}
public Association<P> getAssociation() {
@@ -291,6 +285,14 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
return information.getActualType().getType();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess()
*/
public boolean usePropertyAccess() {
return owner.getType().isInterface() || CAUSE_FIELD.equals(getField());
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
@@ -307,7 +309,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
}
AbstractPersistentProperty<?> that = (AbstractPersistentProperty<?>) obj;
return this.field.equals(that.field);
return this.field == null ? this.propertyDescriptor.equals(that.propertyDescriptor) : this.field.equals(that.field);
}
/*
@@ -316,7 +319,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
*/
@Override
public int hashCode() {
return this.field.hashCode();
return this.field == null ? this.propertyDescriptor.hashCode() : this.field.hashCode();
}
/*
@@ -325,6 +328,6 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
*/
@Override
public String toString() {
return this.field.toString();
return this.field == null ? this.propertyDescriptor.toString() : this.field.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,8 @@ import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.AccessType;
import org.springframework.data.annotation.AccessType.Type;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Reference;
import org.springframework.data.annotation.Transient;
@@ -47,6 +49,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
private final Map<Class<? extends Annotation>, Annotation> annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
private Boolean isTransient;
private boolean usePropertyAccess;
/**
* Creates a new {@link AnnotationBasedPersistentProperty}.
@@ -59,7 +62,11 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
populateAnnotationCache(field);
AccessType accessType = findPropertyOrOwnerAnnotation(AccessType.class);
this.usePropertyAccess = accessType == null ? false : Type.PROPERTY.equals(accessType.value());
this.value = findAnnotation(Value.class);
}
@@ -84,21 +91,29 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
if (annotationCache.containsKey(annotationType) && !annotationCache.get(annotationType).equals(annotation)) {
throw new MappingException(String.format("Ambiguous mapping! Annotation %s configured "
+ "multiple times on accessor methods of property %s in class %s!", annotationType, getName(), getOwner()
.getType().getName()));
+ "multiple times on accessor methods of property %s in class %s!", annotationType.getSimpleName(),
getName(), getOwner().getType().getSimpleName()));
}
annotationCache.put(annotationType, annotation);
}
}
if (field == null) {
return;
}
for (Annotation annotation : field.getAnnotations()) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (!annotationCache.containsKey(annotationType)) {
annotationCache.put(annotationType, annotation);
if (annotationCache.containsKey(annotationType)) {
throw new MappingException(String.format("Ambiguous mapping! Annotation %s configured "
+ "on field %s and one of its accessor methods in class %s!", annotationType.getSimpleName(),
field.getName(), getOwner().getType().getSimpleName()));
}
annotationCache.put(annotationType, annotation);
}
}
@@ -183,7 +198,18 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
}
}
return cacheAndReturn(annotationType, AnnotationUtils.getAnnotation(field, annotationType));
return field == null ? null : cacheAndReturn(annotationType, AnnotationUtils.getAnnotation(field, annotationType));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentProperty#findPropertyOrOwnerAnnotation(java.lang.Class)
*/
@Override
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
A annotation = findAnnotation(annotationType);
return annotation == null ? owner.findAnnotation(annotationType) : annotation;
}
/**
@@ -211,6 +237,15 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
return findAnnotation(annotationType) != null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#usePropertyAccess()
*/
@Override
public boolean usePropertyAccess() {
return super.usePropertyAccess() || usePropertyAccess;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#toString()

View File

@@ -16,6 +16,7 @@
package org.springframework.data.mapping.model;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -23,6 +24,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.AssociationHandler;
@@ -51,7 +53,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
private final Set<P> properties;
private final Set<Association<P>> associations;
private final Map<String, P> propertyCache = new HashMap<String, P>();
private final Map<String, P> propertyCache;
private final Map<Class<? extends Annotation>, Annotation> annotationCache;
private P idProperty;
private P versionProperty;
@@ -70,8 +73,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
* entity.
*
* @param information must not be {@literal null}
* @param comparator
* @param information must not be {@literal null}.
* @param comparator can be {@literal null}.
*/
public BasicPersistentEntity(TypeInformation<T> information, Comparator<P> comparator) {
@@ -82,6 +85,9 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
this.constructor = new PreferredConstructorDiscoverer<T, P>(information, this).getConstructor();
this.associations = comparator == null ? new HashSet<Association<P>>() : new TreeSet<Association<P>>(
new AssociationComparator<P>(comparator));
this.propertyCache = new HashMap<String, P>();
this.annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
}
/*
@@ -305,6 +311,25 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#findAnnotation(java.lang.Class)
*/
@Override
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
A annotation = annotationType.getAnnotation(annotationType);
if (annotation != null) {
return annotation;
}
annotation = AnnotationUtils.findAnnotation(getType(), annotationType);
annotationCache.put(annotationType, annotation);
return annotation;
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 by the original author(s).
* Copyright 2011-2014 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,33 +41,24 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
*
* @param <E>
* @param <T>
* @param bean must not be {@literal null}
* @param conversionService
* @param bean must not be {@literal null}.
* @param conversionService can be {@literal null}.
* @return
*/
public static <E extends PersistentEntity<T, ?>, T> BeanWrapper<E, T> create(T bean,
ConversionService conversionService) {
Assert.notNull(bean, "Wrapped instance must not be null!");
return new BeanWrapper<E, T>(bean, conversionService);
}
private BeanWrapper(T bean, ConversionService conversionService) {
Assert.notNull(bean);
this.bean = bean;
this.conversionService = conversionService;
}
/**
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
* {@link ConversionService} is configured. Will use the accessor method of the given {@link PersistentProperty} if it
* has one or field access otherwise.
*
* @param property must not be {@literal null}.
* @param value
*/
public void setProperty(PersistentProperty<?> property, Object value) {
setProperty(property, value, false);
}
/**
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
* {@link ConversionService} is configured.
@@ -78,23 +69,25 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public void setProperty(PersistentProperty<?> property, Object value, boolean fieldAccessOnly) {
public void setProperty(PersistentProperty<?> property, Object value) {
Method setter = property.getSetter();
try {
if (fieldAccessOnly || null == setter) {
if (!property.usePropertyAccess()) {
Object valueToSet = getPotentiallyConvertedValue(value, property.getType());
ReflectionUtils.makeAccessible(property.getField());
ReflectionUtils.setField(property.getField(), bean, valueToSet);
return;
}
Class<?>[] paramTypes = setter.getParameterTypes();
Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]);
ReflectionUtils.makeAccessible(setter);
ReflectionUtils.invokeMethod(setter, bean, valueToSet);
} else if (property.usePropertyAccess() && setter != null) {
Class<?>[] paramTypes = setter.getParameterTypes();
Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]);
ReflectionUtils.makeAccessible(setter);
ReflectionUtils.invokeMethod(setter, bean, valueToSet);
}
} catch (IllegalStateException e) {
throw new MappingException("Could not set object property!", e);
@@ -109,7 +102,7 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
* @return
*/
public Object getProperty(PersistentProperty<?> property) {
return getProperty(property, property.getType(), false);
return getProperty(property, property.getType());
}
/**
@@ -118,20 +111,23 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
* @param <S>
* @param property must not be {@literal null}.
* @param type
* @param fieldAccessOnly
* @return
*/
public <S> S getProperty(PersistentProperty<?> property, Class<? extends S> type, boolean fieldAccessOnly) {
public <S> S getProperty(PersistentProperty<?> property, Class<? extends S> type) {
try {
Object obj;
Field field = property.getField();
Object obj = null;
Method getter = property.getGetter();
if (fieldAccessOnly || null == getter) {
if (!property.usePropertyAccess()) {
Field field = property.getField();
ReflectionUtils.makeAccessible(field);
obj = ReflectionUtils.getField(field, bean);
} else {
} else if (property.usePropertyAccess() && getter != null) {
ReflectionUtils.makeAccessible(getter);
obj = ReflectionUtils.invokeMethod(getter, bean);
}