broke out to top-level class for readability
This commit is contained in:
parent
c09227a712
commit
cfb387383b
|
@ -42,8 +42,8 @@ import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
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.Property;
|
||||||
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;
|
||||||
|
|
|
@ -19,7 +19,6 @@ import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.convert.TypeDescriptor.Property;
|
|
||||||
|
|
||||||
class BeanPropertyDescriptor extends AbstractDescriptor {
|
class BeanPropertyDescriptor extends AbstractDescriptor {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2011 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.core.convert;
|
||||||
|
|
||||||
|
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.GenericTypeResolver;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of a JavaBeans Property that allows us to avoid a dependency on java.beans.PropertyDescriptor.
|
||||||
|
* java.beans is not available in a number of environments (e.g. Android, Java ME), so this is desirable.
|
||||||
|
* Used to build a TypeDescriptor from a property location.
|
||||||
|
* The built TypeDescriptor can then be used to convert from/to the property type.
|
||||||
|
* @author Keith Donald
|
||||||
|
* @see TypeDescriptor#TypeDescriptor(Property)
|
||||||
|
* @see TypeDescriptor#nested(Property, int)
|
||||||
|
*/
|
||||||
|
public 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object declaring this property, either directly or in a superclass the object extends.
|
||||||
|
*/
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return objectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the property e.g. 'foo'.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property type e.g. java.lang.String.
|
||||||
|
*/
|
||||||
|
public Class<?> getType() {
|
||||||
|
return methodParameter.getParameterType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property getter method e.g. getFoo()
|
||||||
|
*/
|
||||||
|
public Method getReadMethod() {
|
||||||
|
return readMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property setter method e.g. setFoo(String).
|
||||||
|
*/
|
||||||
|
public Method getWriteMethod() {
|
||||||
|
return writeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// package private
|
||||||
|
|
||||||
|
MethodParameter getMethodParameter() {
|
||||||
|
return methodParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
Annotation[] getAnnotations() {
|
||||||
|
return annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal helpers
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,18 +17,13 @@ package org.springframework.core.convert;
|
||||||
|
|
||||||
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.
|
||||||
|
@ -454,165 +449,6 @@ public class TypeDescriptor {
|
||||||
|
|
||||||
// helper public class
|
// 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) {
|
TypeDescriptor(AbstractDescriptor descriptor) {
|
||||||
this.type = descriptor.getType();
|
this.type = descriptor.getType();
|
||||||
this.elementType = descriptor.getElementType();
|
this.elementType = descriptor.getElementType();
|
||||||
|
|
|
@ -36,7 +36,6 @@ 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
|
||||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.convert.Property;
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue