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.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.Property;
|
||||
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;
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.lang.annotation.Annotation;
|
|||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor.Property;
|
||||
|
||||
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.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.
|
||||
|
@ -454,165 +449,6 @@ public class TypeDescriptor {
|
|||
|
||||
// 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) {
|
||||
this.type = descriptor.getType();
|
||||
this.elementType = descriptor.getElementType();
|
||||
|
|
|
@ -36,7 +36,6 @@ 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
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.Property;
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue