removed dependency on java.beans
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4455 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
911eb5fca8
commit
89096b46b8
|
|
@ -43,6 +43,7 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.convert.ConversionException;
|
import org.springframework.core.convert.ConversionException;
|
||||||
import org.springframework.core.convert.ConverterNotFoundException;
|
import org.springframework.core.convert.ConverterNotFoundException;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
import org.springframework.core.convert.TypeDescriptor.Property;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
@ -369,11 +370,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
if (pd != null) {
|
if (pd != null) {
|
||||||
if (tokens.keys != null) {
|
if (tokens.keys != null) {
|
||||||
if (pd.getReadMethod() != null || pd.getWriteMethod() != 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 {
|
} else {
|
||||||
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
|
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 {
|
throws TypeMismatchException {
|
||||||
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
|
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
|
||||||
Class<?> beanClass = gpd.getBeanClass();
|
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)) {
|
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||||
oldValue = Array.get(propValue, arrayIndex);
|
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
|
// TODO review this grow algorithm along side the null gap algorithm for setting lists below ... the two are inconsistent
|
||||||
propValue = growArrayIfNecessary(propValue, arrayIndex, actualName);
|
propValue = growArrayIfNecessary(propValue, arrayIndex, actualName);
|
||||||
Array.set(propValue, arrayIndex, convertedValue);
|
Array.set(propValue, arrayIndex, convertedValue);
|
||||||
|
|
@ -968,7 +969,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||||
oldValue = list.get(index);
|
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()) {
|
if (index < list.size()) {
|
||||||
list.set(index, convertedValue);
|
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
|
// Pass full property name and old value in here, since we want full
|
||||||
// conversion ability for map values.
|
// conversion ability for map values.
|
||||||
Object convertedMapValue = convertIfNecessary(
|
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);
|
map.put(convertedMapKey, convertedMapValue);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -1168,4 +1169,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
public String[] keys;
|
public String[] keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Property property(PropertyDescriptor pd) {
|
||||||
|
GenericTypeAwarePropertyDescriptor typeAware = (GenericTypeAwarePropertyDescriptor) pd;
|
||||||
|
return new Property(typeAware.getBeanClass(), typeAware.getReadMethod(), typeAware.getWriteMethod());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ abstract class AbstractDescriptor {
|
||||||
|
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
|
|
||||||
public AbstractDescriptor(Class<?> type) {
|
protected AbstractDescriptor(Class<?> type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new IllegalArgumentException("type cannot be null");
|
throw new IllegalArgumentException("type cannot be null");
|
||||||
}
|
}
|
||||||
|
|
@ -93,15 +93,15 @@ abstract class AbstractDescriptor {
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private boolean isCollection() {
|
private boolean isCollection() {
|
||||||
return getType() != null && Collection.class.isAssignableFrom(getType());
|
return Collection.class.isAssignableFrom(getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isArray() {
|
private boolean isArray() {
|
||||||
return getType() != null && getType().isArray();
|
return getType().isArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMap() {
|
private boolean isMap() {
|
||||||
return getType() != null && Map.class.isAssignableFrom(getType());
|
return Map.class.isAssignableFrom(getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -15,35 +15,25 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.core.convert;
|
package org.springframework.core.convert;
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.lang.annotation.Annotation;
|
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.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.core.convert.TypeDescriptor.Property;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
class BeanPropertyDescriptor extends AbstractDescriptor {
|
class BeanPropertyDescriptor extends AbstractDescriptor {
|
||||||
|
|
||||||
private final Class<?> beanClass;
|
private final Property property;
|
||||||
|
|
||||||
private final PropertyDescriptor property;
|
|
||||||
|
|
||||||
private final MethodParameter methodParameter;
|
private final MethodParameter methodParameter;
|
||||||
|
|
||||||
private final Annotation[] annotations;
|
private final Annotation[] annotations;
|
||||||
|
|
||||||
public BeanPropertyDescriptor(Class<?> beanClass, PropertyDescriptor property) {
|
public BeanPropertyDescriptor(Property property) {
|
||||||
super(property.getPropertyType());
|
super(property.getType());
|
||||||
this.beanClass = beanClass;
|
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.methodParameter = resolveMethodParameter();
|
this.methodParameter = property.getMethodParameter();
|
||||||
this.annotations = resolveAnnotations();
|
this.annotations = property.getAnnotations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -71,79 +61,13 @@ class BeanPropertyDescriptor extends AbstractDescriptor {
|
||||||
MethodParameter methodParameter = new MethodParameter(this.methodParameter);
|
MethodParameter methodParameter = new MethodParameter(this.methodParameter);
|
||||||
methodParameter.increaseNestingLevel();
|
methodParameter.increaseNestingLevel();
|
||||||
methodParameter.setTypeIndexForCurrentLevel(typeIndex);
|
methodParameter.setTypeIndexForCurrentLevel(typeIndex);
|
||||||
return new BeanPropertyDescriptor(type, beanClass, property, methodParameter, annotations);
|
return new BeanPropertyDescriptor(type, property, methodParameter, annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
|
|
||||||
private MethodParameter resolveMethodParameter() {
|
private BeanPropertyDescriptor(Class<?> type, Property propertyDescriptor, MethodParameter methodParameter, Annotation[] annotations) {
|
||||||
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) {
|
|
||||||
super(type);
|
super(type);
|
||||||
this.beanClass = beanClass;
|
|
||||||
this.property = propertyDescriptor;
|
this.property = propertyDescriptor;
|
||||||
this.methodParameter = methodParameter;
|
this.methodParameter = methodParameter;
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,22 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.core.convert;
|
package org.springframework.core.convert;
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context about a type to convert from or to.
|
* 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.
|
* Create a new type descriptor for a bean property.
|
||||||
* Use this constructor when a target conversion point is a property on a Java class.
|
* 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
|
||||||
* @param property the property descriptor
|
|
||||||
*/
|
*/
|
||||||
public TypeDescriptor(Class<?> beanClass, PropertyDescriptor property) {
|
public TypeDescriptor(Property property) {
|
||||||
this(new BeanPropertyDescriptor(beanClass, property));
|
this(new BeanPropertyDescriptor(property));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,8 +184,8 @@ public class TypeDescriptor {
|
||||||
* @return the nested type descriptor
|
* @return the nested type descriptor
|
||||||
* @throws IllegalArgumentException if the property is not of a collection, array, or map type.
|
* @throws IllegalArgumentException if the property is not of a collection, array, or map type.
|
||||||
*/
|
*/
|
||||||
public static TypeDescriptor nested(Class<?> beanClass, PropertyDescriptor property, int nestingLevel) {
|
public static TypeDescriptor nested(Property property, int nestingLevel) {
|
||||||
return nested(new BeanPropertyDescriptor(beanClass, property), nestingLevel);
|
return nested(new BeanPropertyDescriptor(property), nestingLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -415,17 +417,17 @@ public class TypeDescriptor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TypeDescriptor other = (TypeDescriptor) obj;
|
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) {
|
if (!annotatedTypeEquals) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isCollection() || isArray()) {
|
if (isCollection() || isArray()) {
|
||||||
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
|
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
|
||||||
}
|
} else if (isMap()) {
|
||||||
else if (isMap()) {
|
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType())
|
||||||
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) && ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
|
&& ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,13 +446,171 @@ public class TypeDescriptor {
|
||||||
if (isMap()) {
|
if (isMap()) {
|
||||||
builder.append("<").append(wildcard(getMapKeyType()));
|
builder.append("<").append(wildcard(getMapKeyType()));
|
||||||
builder.append(", ").append(wildcard(getMapValueType())).append(">");
|
builder.append(", ").append(wildcard(getMapValueType())).append(">");
|
||||||
}
|
} else if (isCollection()) {
|
||||||
else if (isCollection()) {
|
|
||||||
builder.append("<").append(wildcard(getElementType())).append(">");
|
builder.append("<").append(wildcard(getElementType())).append(">");
|
||||||
}
|
}
|
||||||
return builder.toString();
|
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
|
// package private
|
||||||
|
|
||||||
TypeDescriptor(AbstractDescriptor descriptor) {
|
TypeDescriptor(AbstractDescriptor descriptor) {
|
||||||
|
|
@ -479,7 +639,8 @@ public class TypeDescriptor {
|
||||||
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
|
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.type = type;
|
||||||
this.elementType = elementType;
|
this.elementType = elementType;
|
||||||
this.mapKeyType = mapKeyType;
|
this.mapKeyType = mapKeyType;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -37,6 +36,7 @@ import java.util.Map;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.convert.TypeDescriptor.Property;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
|
@ -205,8 +205,8 @@ public class TypeDescriptorTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyComplex() throws Exception {
|
public void propertyComplex() throws Exception {
|
||||||
PropertyDescriptor property = new PropertyDescriptor("complexProperty", getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
|
Property property = new Property(getClass(), getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
|
||||||
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
|
TypeDescriptor desc = new TypeDescriptor(property);
|
||||||
assertEquals(String.class, desc.getMapKeyType().getType());
|
assertEquals(String.class, desc.getMapKeyType().getType());
|
||||||
assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
|
assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
|
||||||
}
|
}
|
||||||
|
|
@ -222,16 +222,16 @@ public class TypeDescriptorTests {
|
||||||
@Test
|
@Test
|
||||||
public void propertyGenericType() throws Exception {
|
public void propertyGenericType() throws Exception {
|
||||||
GenericType<Integer> genericBean = new IntegerType();
|
GenericType<Integer> genericBean = new IntegerType();
|
||||||
PropertyDescriptor property = new PropertyDescriptor("property", genericBean.getClass().getMethod("getProperty", null), genericBean.getClass().getMethod("setProperty", Integer.class));
|
Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty", null), genericBean.getClass().getMethod("setProperty", Integer.class));
|
||||||
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
|
TypeDescriptor desc = new TypeDescriptor(property);
|
||||||
assertEquals(Integer.class, desc.getType());
|
assertEquals(Integer.class, desc.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyGenericTypeList() throws Exception {
|
public void propertyGenericTypeList() throws Exception {
|
||||||
GenericType<Integer> genericBean = new IntegerType();
|
GenericType<Integer> genericBean = new IntegerType();
|
||||||
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
||||||
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
|
TypeDescriptor desc = new TypeDescriptor(property);
|
||||||
assertEquals(List.class, desc.getType());
|
assertEquals(List.class, desc.getType());
|
||||||
assertEquals(Integer.class, desc.getElementType().getType());
|
assertEquals(Integer.class, desc.getElementType().getType());
|
||||||
}
|
}
|
||||||
|
|
@ -274,8 +274,8 @@ public class TypeDescriptorTests {
|
||||||
@Test
|
@Test
|
||||||
public void propertyGenericClassList() throws Exception {
|
public void propertyGenericClassList() throws Exception {
|
||||||
IntegerClass genericBean = new IntegerClass();
|
IntegerClass genericBean = new IntegerClass();
|
||||||
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
||||||
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
|
TypeDescriptor desc = new TypeDescriptor(property);
|
||||||
assertEquals(List.class, desc.getType());
|
assertEquals(List.class, desc.getType());
|
||||||
assertEquals(Integer.class, desc.getElementType().getType());
|
assertEquals(Integer.class, desc.getElementType().getType());
|
||||||
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
||||||
|
|
@ -306,8 +306,9 @@ public class TypeDescriptorTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void property() throws Exception {
|
public void property() throws Exception {
|
||||||
PropertyDescriptor property = new PropertyDescriptor("property", getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
|
Property property = new Property(getClass(), getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
|
||||||
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
|
TypeDescriptor desc = new TypeDescriptor(property);
|
||||||
|
assertEquals(Map.class, desc.getType());
|
||||||
assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
|
assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
|
||||||
assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
|
assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
|
||||||
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
||||||
|
|
@ -573,8 +574,8 @@ public class TypeDescriptorTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nestedPropertyTypeMapTwoLevels() throws Exception {
|
public void nestedPropertyTypeMapTwoLevels() throws Exception {
|
||||||
PropertyDescriptor property = new PropertyDescriptor("test4", getClass().getMethod("getTest4", null), getClass().getMethod("setTest4", List.class));
|
Property property = new Property(getClass(), getClass().getMethod("getTest4", null), getClass().getMethod("setTest4", List.class));
|
||||||
TypeDescriptor t1 = TypeDescriptor.nested(getClass(), property, 2);
|
TypeDescriptor t1 = TypeDescriptor.nested(property, 2);
|
||||||
assertEquals(String.class, t1.getType());
|
assertEquals(String.class, t1.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.expression.spel.support;
|
package org.springframework.expression.spel.support;
|
||||||
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
|
|
@ -28,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
import org.springframework.core.convert.TypeDescriptor.Property;
|
||||||
import org.springframework.expression.AccessException;
|
import org.springframework.expression.AccessException;
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.EvaluationException;
|
import org.springframework.expression.EvaluationException;
|
||||||
|
|
@ -75,18 +74,13 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
Method method = findGetterForProperty(name, type, target instanceof Class);
|
Method method = findGetterForProperty(name, type, target instanceof Class);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
// Treat it like a property
|
// Treat it like a property
|
||||||
try {
|
|
||||||
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
||||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
|
Property property = new Property(type, method, null);
|
||||||
TypeDescriptor typeDescriptor = new TypeDescriptor(type, propertyDescriptor);
|
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||||
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
|
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
|
||||||
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
|
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (IntrospectionException ex) {
|
|
||||||
throw new AccessException("Unable to access property '" + name + "' through getter " + method, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Field field = findField(name, type, target instanceof Class);
|
Field field = findField(name, type, target instanceof Class);
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
|
|
@ -122,18 +116,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
// TODO remove the duplication here between canRead and read
|
// TODO remove the duplication here between canRead and read
|
||||||
// Treat it like a property
|
// Treat it like a property
|
||||||
try {
|
|
||||||
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
||||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
|
Property property = new Property(type, method, null);
|
||||||
TypeDescriptor typeDescriptor = new TypeDescriptor(type, propertyDescriptor);
|
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||||
invoker = new InvokerPair(method, typeDescriptor);
|
invoker = new InvokerPair(method, typeDescriptor);
|
||||||
this.readerCache.put(cacheKey, invoker);
|
this.readerCache.put(cacheKey, invoker);
|
||||||
}
|
}
|
||||||
catch (IntrospectionException ex) {
|
|
||||||
throw new AccessException(
|
|
||||||
"Unable to access property '" + name + "' through getter " + method, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -183,14 +171,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
Method method = findSetterForProperty(name, type, target instanceof Class);
|
Method method = findSetterForProperty(name, type, target instanceof Class);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
// Treat it like a property
|
// Treat it like a property
|
||||||
PropertyDescriptor propertyDescriptor = null;
|
Property property = new Property(type, null, method);
|
||||||
try {
|
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||||
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);
|
|
||||||
this.writerCache.put(cacheKey, method);
|
this.writerCache.put(cacheKey, method);
|
||||||
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
|
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue