From cfb387383bdd921f16edca1da2ee7fde5f61f39a Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Sun, 5 Jun 2011 08:37:08 +0000 Subject: [PATCH] broke out to top-level class for readability --- .../beans/BeanWrapperImpl.java | 2 +- .../core/convert/BeanPropertyDescriptor.java | 1 - .../core/convert/Property.java | 212 ++++++++++++++++++ .../core/convert/TypeDescriptor.java | 164 -------------- .../core/convert/TypeDescriptorTests.java | 1 - .../support/ReflectivePropertyAccessor.java | 2 +- 6 files changed, 214 insertions(+), 168 deletions(-) create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/Property.java diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java index 19e58fc4b78..26f7390f7b0 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java @@ -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; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/BeanPropertyDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/BeanPropertyDescriptor.java index 9bf16f667ba..b7358d07a99 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/BeanPropertyDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/BeanPropertyDescriptor.java @@ -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 { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/Property.java b/org.springframework.core/src/main/java/org/springframework/core/convert/Property.java new file mode 100644 index 00000000000..e350e4cb6d4 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/Property.java @@ -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, Annotation> annMap = new LinkedHashMap, 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(); + } + } + +} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index a614595af01..37e8bb92a9e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -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, Annotation> annMap = new LinkedHashMap, 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(); diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java index fbf978610de..d6bbceb9879 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java @@ -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 diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 6049c31d331..e6cd3740827 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -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;