broke out to top-level class for readability

This commit is contained in:
Keith Donald 2011-06-05 08:37:08 +00:00
parent c09227a712
commit cfb387383b
6 changed files with 214 additions and 168 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -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();

View File

@ -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

View File

@ -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;