removed dependency on java.beans

This commit is contained in:
Keith Donald 2011-06-05 08:29:14 +00:00
parent 94d690fb2c
commit c09227a712
6 changed files with 246 additions and 172 deletions

View File

@ -43,6 +43,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.TypeDescriptor.Property;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@ -369,11 +370,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (pd != null) {
if (tokens.keys != null) {
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
return TypeDescriptor.nested(nestedBw.getWrappedClass(), pd, tokens.keys.length);
return TypeDescriptor.nested(property(pd), tokens.keys.length);
}
} else {
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
return new TypeDescriptor(nestedBw.getWrappedClass(), pd);
return new TypeDescriptor(property(pd));
}
}
}
@ -493,7 +494,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
throws TypeMismatchException {
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
Class<?> beanClass = gpd.getBeanClass();
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(beanClass, pd));
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(property(pd)));
}
@ -948,7 +949,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
// TODO review this grow algorithm along side the null gap algorithm for setting lists below ... the two are inconsistent
propValue = growArrayIfNecessary(propValue, arrayIndex, actualName);
Array.set(propValue, arrayIndex, convertedValue);
@ -968,7 +969,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
if (index < list.size()) {
list.set(index, convertedValue);
}
@ -1005,7 +1006,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
// Pass full property name and old value in here, since we want full
// conversion ability for map values.
Object convertedMapValue = convertIfNecessary(
propertyName, oldValue, pv.getValue(), mapValueType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
propertyName, oldValue, pv.getValue(), mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}
else {
@ -1167,5 +1168,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
public String[] keys;
}
private Property property(PropertyDescriptor pd) {
GenericTypeAwarePropertyDescriptor typeAware = (GenericTypeAwarePropertyDescriptor) pd;
return new Property(typeAware.getBeanClass(), typeAware.getReadMethod(), typeAware.getWriteMethod());
}
}

View File

@ -23,7 +23,7 @@ abstract class AbstractDescriptor {
private final Class<?> type;
public AbstractDescriptor(Class<?> type) {
protected AbstractDescriptor(Class<?> type) {
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
@ -93,15 +93,15 @@ abstract class AbstractDescriptor {
// internal helpers
private boolean isCollection() {
return getType() != null && Collection.class.isAssignableFrom(getType());
return Collection.class.isAssignableFrom(getType());
}
private boolean isArray() {
return getType() != null && getType().isArray();
return getType().isArray();
}
private boolean isMap() {
return getType() != null && Map.class.isAssignableFrom(getType());
return Map.class.isAssignableFrom(getType());
}
}

View File

@ -15,35 +15,25 @@
*/
package org.springframework.core.convert;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.core.convert.TypeDescriptor.Property;
class BeanPropertyDescriptor extends AbstractDescriptor {
private final Class<?> beanClass;
private final PropertyDescriptor property;
private final Property property;
private final MethodParameter methodParameter;
private final Annotation[] annotations;
public BeanPropertyDescriptor(Class<?> beanClass, PropertyDescriptor property) {
super(property.getPropertyType());
this.beanClass = beanClass;
public BeanPropertyDescriptor(Property property) {
super(property.getType());
this.property = property;
this.methodParameter = resolveMethodParameter();
this.annotations = resolveAnnotations();
this.methodParameter = property.getMethodParameter();
this.annotations = property.getAnnotations();
}
@Override
@ -71,79 +61,13 @@ class BeanPropertyDescriptor extends AbstractDescriptor {
MethodParameter methodParameter = new MethodParameter(this.methodParameter);
methodParameter.increaseNestingLevel();
methodParameter.setTypeIndexForCurrentLevel(typeIndex);
return new BeanPropertyDescriptor(type, beanClass, property, methodParameter, annotations);
return new BeanPropertyDescriptor(type, property, methodParameter, annotations);
}
// internal
private MethodParameter resolveMethodParameter() {
MethodParameter parameter = parameterForPropertyMethod();
// needed to resolve generic property types that parameterized by sub-classes e.g. T getFoo();
GenericTypeResolver.resolveParameterType(parameter, beanClass);
return parameter;
}
private MethodParameter parameterForPropertyMethod() {
if (property.getReadMethod() != null) {
return new MethodParameter(property.getReadMethod(), -1);
} else if (property.getWriteMethod() != null) {
return new MethodParameter(property.getWriteMethod(), 0);
} else {
throw new IllegalArgumentException("Property is neither readable or writeable");
}
}
private Annotation[] resolveAnnotations() {
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
Method readMethod = this.property.getReadMethod();
if (readMethod != null) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Method writeMethod = this.property.getWriteMethod();
if (writeMethod != null) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Field field = getField();
if (field != null) {
for (Annotation ann : field.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
return annMap.values().toArray(new Annotation[annMap.size()]);
}
private Field getField() {
String name = this.property.getName();
if (!StringUtils.hasLength(name)) {
return null;
}
Class<?> declaringClass = declaringClass();
Field field = ReflectionUtils.findField(declaringClass, name);
if (field == null) {
// Same lenient fallback checking as in CachedIntrospectionResults...
field = ReflectionUtils.findField(declaringClass, name.substring(0, 1).toLowerCase() + name.substring(1));
if (field == null) {
field = ReflectionUtils.findField(declaringClass, name.substring(0, 1).toUpperCase() + name.substring(1));
}
}
return field;
}
private Class<?> declaringClass() {
if (this.property.getReadMethod() != null) {
return this.property.getReadMethod().getDeclaringClass();
} else {
return this.property.getWriteMethod().getDeclaringClass();
}
}
private BeanPropertyDescriptor(Class<?> type, Class<?> beanClass, java.beans.PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Annotation[] annotations) {
private BeanPropertyDescriptor(Class<?> type, Property propertyDescriptor, MethodParameter methodParameter, Annotation[] annotations) {
super(type);
this.beanClass = beanClass;
this.property = propertyDescriptor;
this.methodParameter = methodParameter;
this.annotations = annotations;

View File

@ -13,19 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.convert;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Context about a type to convert from or to.
@ -91,11 +94,10 @@ public class TypeDescriptor {
/**
* Create a new type descriptor for a bean property.
* Use this constructor when a target conversion point is a property on a Java class.
* @param beanClass the class that declares the property
* @param property the property descriptor
* @param property the property
*/
public TypeDescriptor(Class<?> beanClass, PropertyDescriptor property) {
this(new BeanPropertyDescriptor(beanClass, property));
public TypeDescriptor(Property property) {
this(new BeanPropertyDescriptor(property));
}
/**
@ -140,7 +142,7 @@ public class TypeDescriptor {
}
return new TypeDescriptor(mapType, keyType, valueType);
}
/**
* Creates a type descriptor for a nested type declared within the method parameter.
* For example, if the methodParameter is a List&lt;String&gt; and the nestingLevel is 1, the nested type descriptor will be String.class.
@ -182,8 +184,8 @@ public class TypeDescriptor {
* @return the nested type descriptor
* @throws IllegalArgumentException if the property is not of a collection, array, or map type.
*/
public static TypeDescriptor nested(Class<?> beanClass, PropertyDescriptor property, int nestingLevel) {
return nested(new BeanPropertyDescriptor(beanClass, property), nestingLevel);
public static TypeDescriptor nested(Property property, int nestingLevel) {
return nested(new BeanPropertyDescriptor(property), nestingLevel);
}
/**
@ -196,7 +198,7 @@ public class TypeDescriptor {
public static TypeDescriptor forObject(Object source) {
return source != null ? valueOf(source.getClass()) : null;
}
/**
* Determine the declared (non-generic) type of the wrapped parameter/field.
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
@ -230,7 +232,7 @@ public class TypeDescriptor {
}
return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations);
}
/**
* Returns the name of this type: the fully qualified class name.
*/
@ -288,7 +290,7 @@ public class TypeDescriptor {
}
// indexable type descriptor operations
/**
* Is this type a {@link Collection} type?
*/
@ -336,7 +338,7 @@ public class TypeDescriptor {
}
// map type descriptor operations
/**
* Is this type a {@link Map} type?
*/
@ -406,7 +408,7 @@ public class TypeDescriptor {
}
// extending Object
public boolean equals(Object obj) {
if (this == obj) {
return true;
@ -415,17 +417,17 @@ public class TypeDescriptor {
return false;
}
TypeDescriptor other = (TypeDescriptor) obj;
boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType())
&& ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
if (!annotatedTypeEquals) {
return false;
}
if (isCollection() || isArray()) {
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
}
else if (isMap()) {
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) && ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
}
else {
} else if (isMap()) {
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType())
&& ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
} else {
return true;
}
}
@ -444,13 +446,171 @@ public class TypeDescriptor {
if (isMap()) {
builder.append("<").append(wildcard(getMapKeyType()));
builder.append(", ").append(wildcard(getMapValueType())).append(">");
}
else if (isCollection()) {
} else if (isCollection()) {
builder.append("<").append(wildcard(getElementType())).append(">");
}
return builder.toString();
}
// helper public class
public static final class Property {
private final Class<?> objectType;
private final Method readMethod;
private final Method writeMethod;
private final String name;
private final MethodParameter methodParameter;
private final Annotation[] annotations;
public Property(Class<?> objectType, Method readMethod, Method writeMethod) {
this.objectType = objectType;
this.readMethod = readMethod;
this.writeMethod = writeMethod;
this.methodParameter = resolveMethodParameter();
this.name = resolveName();
this.annotations = resolveAnnotations();
}
public Class<?> getObjectType() {
return objectType;
}
public String getName() {
return name;
}
public Class<?> getType() {
return methodParameter.getParameterType();
}
public Method getReadMethod() {
return readMethod;
}
public Method getWriteMethod() {
return writeMethod;
}
MethodParameter getMethodParameter() {
return methodParameter;
}
Annotation[] getAnnotations() {
return annotations;
}
private String resolveName() {
if (readMethod != null) {
int index = readMethod.getName().indexOf("get");
if (index != -1) {
index += 3;
} else {
index = readMethod.getName().indexOf("is");
if (index == -1) {
throw new IllegalArgumentException("Not a getter method");
}
index += 2;
}
return StringUtils.uncapitalize(readMethod.getName().substring(index));
} else {
int index = writeMethod.getName().indexOf("set") + 3;
if (index == -1) {
throw new IllegalArgumentException("Not a setter method");
}
return StringUtils.uncapitalize(writeMethod.getName().substring(index));
}
}
private MethodParameter resolveMethodParameter() {
MethodParameter read = resolveReadMethodParameter();
MethodParameter write = resolveWriteMethodParameter();
if (read == null && write == null) {
throw new IllegalStateException("Property is neither readable or writeable");
}
if (read != null && write != null && !read.getParameterType().equals(write.getParameterType())) {
throw new IllegalStateException("Read and write parameter types are not the same");
}
return read != null ? read : write;
}
private MethodParameter resolveReadMethodParameter() {
if (getReadMethod() == null) {
return null;
}
return resolveParameterType(new MethodParameter(getReadMethod(), -1));
}
private MethodParameter resolveWriteMethodParameter() {
if (getWriteMethod() == null) {
return null;
}
return resolveParameterType(new MethodParameter(getWriteMethod(), 0));
}
private MethodParameter resolveParameterType(MethodParameter parameter) {
// needed to resolve generic property types that parameterized by sub-classes e.g. T getFoo();
GenericTypeResolver.resolveParameterType(parameter, getObjectType());
return parameter;
}
private Annotation[] resolveAnnotations() {
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
Method readMethod = getReadMethod();
if (readMethod != null) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Method writeMethod = getWriteMethod();
if (writeMethod != null) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Field field = getField();
if (field != null) {
for (Annotation ann : field.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
return annMap.values().toArray(new Annotation[annMap.size()]);
}
private Field getField() {
String name = getName();
if (!StringUtils.hasLength(name)) {
return null;
}
Class<?> declaringClass = declaringClass();
Field field = ReflectionUtils.findField(declaringClass, name);
if (field == null) {
// Same lenient fallback checking as in CachedIntrospectionResults...
field = ReflectionUtils.findField(declaringClass,
name.substring(0, 1).toLowerCase() + name.substring(1));
if (field == null) {
field = ReflectionUtils.findField(declaringClass,
name.substring(0, 1).toUpperCase() + name.substring(1));
}
}
return field;
}
private Class<?> declaringClass() {
if (getReadMethod() != null) {
return getReadMethod().getDeclaringClass();
} else {
return getWriteMethod().getDeclaringClass();
}
}
}
// package private
TypeDescriptor(AbstractDescriptor descriptor) {
@ -464,7 +624,7 @@ public class TypeDescriptor {
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY;
}
// internal constructors
private TypeDescriptor(Class<?> type) {
@ -479,7 +639,8 @@ public class TypeDescriptor {
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
}
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType, Annotation[] annotations) {
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType,
TypeDescriptor mapValueType, Annotation[] annotations) {
this.type = type;
this.elementType = elementType;
this.mapKeyType = mapKeyType;
@ -494,7 +655,7 @@ public class TypeDescriptor {
return null;
}
}
return new TypeDescriptor(descriptor);
return new TypeDescriptor(descriptor);
}
// internal helpers
@ -507,7 +668,7 @@ public class TypeDescriptor {
if (keyType == null) {
return false;
}
return keyType.isAssignableTo(targetKeyType);
return keyType.isAssignableTo(targetKeyType);
}
private boolean collectionElementsAssignable(TypeDescriptor targetElementType) {
@ -518,9 +679,9 @@ public class TypeDescriptor {
if (elementType == null) {
return false;
}
return elementType.isAssignableTo(targetElementType);
return elementType.isAssignableTo(targetElementType);
}
private boolean mapValuesAssignable(TypeDescriptor targetValueType) {
TypeDescriptor valueType = getMapValueType();
if (targetValueType == null) {
@ -529,21 +690,21 @@ public class TypeDescriptor {
if (valueType == null) {
return false;
}
return valueType.isAssignableTo(targetValueType);
return valueType.isAssignableTo(targetValueType);
}
private void assertCollectionOrArray() {
if (!isCollection() && !isArray()) {
throw new IllegalStateException("Not a java.util.Collection or Array");
}
}
}
private void assertMap() {
if (!isMap()) {
throw new IllegalStateException("Not a java.util.Map");
}
}
}
private String wildcard(TypeDescriptor nestedType) {
return nestedType != null ? nestedType.toString() : "?";
}

View File

@ -22,7 +22,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.beans.PropertyDescriptor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -37,6 +36,7 @@ import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor.Property;
/**
* @author Keith Donald
@ -205,8 +205,8 @@ public class TypeDescriptorTests {
@Test
public void propertyComplex() throws Exception {
PropertyDescriptor property = new PropertyDescriptor("complexProperty", getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
Property property = new Property(getClass(), getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(String.class, desc.getMapKeyType().getType());
assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
}
@ -222,16 +222,16 @@ public class TypeDescriptorTests {
@Test
public void propertyGenericType() throws Exception {
GenericType<Integer> genericBean = new IntegerType();
PropertyDescriptor property = new PropertyDescriptor("property", genericBean.getClass().getMethod("getProperty", null), genericBean.getClass().getMethod("setProperty", Integer.class));
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty", null), genericBean.getClass().getMethod("setProperty", Integer.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(Integer.class, desc.getType());
}
@Test
public void propertyGenericTypeList() throws Exception {
GenericType<Integer> genericBean = new IntegerType();
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementType().getType());
}
@ -274,8 +274,8 @@ public class TypeDescriptorTests {
@Test
public void propertyGenericClassList() throws Exception {
IntegerClass genericBean = new IntegerClass();
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementType().getType());
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
@ -306,8 +306,9 @@ public class TypeDescriptorTests {
@Test
public void property() throws Exception {
PropertyDescriptor property = new PropertyDescriptor("property", getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
Property property = new Property(getClass(), getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(Map.class, desc.getType());
assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
@ -573,8 +574,8 @@ public class TypeDescriptorTests {
@Test
public void nestedPropertyTypeMapTwoLevels() throws Exception {
PropertyDescriptor property = new PropertyDescriptor("test4", getClass().getMethod("getTest4", null), getClass().getMethod("setTest4", List.class));
TypeDescriptor t1 = TypeDescriptor.nested(getClass(), property, 2);
Property property = new Property(getClass(), getClass().getMethod("getTest4", null), getClass().getMethod("setTest4", List.class));
TypeDescriptor t1 = TypeDescriptor.nested(property, 2);
assertEquals(String.class, t1.getType());
}

View File

@ -16,8 +16,6 @@
package org.springframework.expression.spel.support;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
@ -28,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.TypeDescriptor.Property;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@ -75,17 +74,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
Method method = findGetterForProperty(name, type, target instanceof Class);
if (method != null) {
// Treat it like a property
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(type, propertyDescriptor);
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter " + method, ex);
}
// The readerCache will only contain gettable properties (let's not worry about setters for now)
Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
else {
Field field = findField(name, type, target instanceof Class);
@ -122,17 +116,11 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method != null) {
// TODO remove the duplication here between canRead and read
// Treat it like a property
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(type, propertyDescriptor);
invoker = new InvokerPair(method, typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
catch (IntrospectionException ex) {
throw new AccessException(
"Unable to access property '" + name + "' through getter " + method, ex);
}
// The readerCache will only contain gettable properties (let's not worry about setters for now)
Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
invoker = new InvokerPair(method, typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
}
if (method != null) {
@ -183,14 +171,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
Method method = findSetterForProperty(name, type, target instanceof Class);
if (method != null) {
// Treat it like a property
PropertyDescriptor propertyDescriptor = null;
try {
propertyDescriptor = new PropertyDescriptor(name, null, method);
}
catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through setter "+method, ex);
}
TypeDescriptor typeDescriptor = new TypeDescriptor(type, propertyDescriptor);
Property property = new Property(type, null, method);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;