diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index b9b05e18788..449ea5a0a00 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -194,7 +194,7 @@ class TypeConverterDelegate { // No custom editor but custom ConversionService specified? ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); if (editor == null && conversionService != null && convertedValue != null) { - TypeDescriptor sourceTypeDesc = new TypeDescriptor(convertedValue); + TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue); if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) { return (T) conversionService.convert(convertedValue, sourceTypeDesc, typeDescriptor); } 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 88036835eba..eb01543c825 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 @@ -43,39 +43,38 @@ public class TypeDescriptor { private static final Map, TypeDescriptor> typeDescriptorCache = new HashMap, TypeDescriptor>(); static { + typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class)); + typeDescriptorCache.put(Boolean.class, new TypeDescriptor(Boolean.class)); + typeDescriptorCache.put(byte.class, new TypeDescriptor(byte.class)); typeDescriptorCache.put(Byte.class, new TypeDescriptor(Byte.class)); typeDescriptorCache.put(char.class, new TypeDescriptor(char.class)); typeDescriptorCache.put(Character.class, new TypeDescriptor(Character.class)); - typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class)); - typeDescriptorCache.put(Boolean.class, new TypeDescriptor(Boolean.class)); - - typeDescriptorCache.put(short.class, new TypeDescriptor(short.class)); - typeDescriptorCache.put(Short.class, new TypeDescriptor(Short.class)); - + typeDescriptorCache.put(double.class, new TypeDescriptor(double.class)); + typeDescriptorCache.put(Double.class, new TypeDescriptor(Double.class)); + + typeDescriptorCache.put(float.class, new TypeDescriptor(float.class)); + typeDescriptorCache.put(Float.class, new TypeDescriptor(Float.class)); + typeDescriptorCache.put(int.class, new TypeDescriptor(int.class)); typeDescriptorCache.put(Integer.class, new TypeDescriptor(Integer.class)); typeDescriptorCache.put(long.class, new TypeDescriptor(long.class)); typeDescriptorCache.put(Long.class, new TypeDescriptor(Long.class)); - typeDescriptorCache.put(float.class, new TypeDescriptor(float.class)); - typeDescriptorCache.put(Float.class, new TypeDescriptor(Float.class)); - - typeDescriptorCache.put(double.class, new TypeDescriptor(double.class)); - typeDescriptorCache.put(Double.class, new TypeDescriptor(Double.class)); - + typeDescriptorCache.put(short.class, new TypeDescriptor(short.class)); + typeDescriptorCache.put(Short.class, new TypeDescriptor(Short.class)); + typeDescriptorCache.put(String.class, new TypeDescriptor(String.class)); } + private Object value; private Class type; - private TypeDescriptor elementType; - private MethodParameter methodParameter; private Field field; @@ -83,17 +82,6 @@ public class TypeDescriptor { private Annotation[] cachedFieldAnnotations; - /** - * Create a new descriptor for the given type. - *

Use this constructor when a conversion point comes from a plain source type, - * where no additional context is available. - * @param type the actual type to wrap - */ - public TypeDescriptor(Class type) { - Assert.notNull(type, "Type must not be null"); - this.type = type; - } - /** * Create a new type descriptor from a method or constructor parameter. *

Use this constructor when a target conversion point originates from a method parameter, @@ -115,18 +103,6 @@ public class TypeDescriptor { this.field = field; } - /** - * Create a new descriptor for the type of the given value. - *

Use this constructor when a conversion point comes from a source such as a Map or - * Collection, where no additional context is available but elements can be introspected. - * @param type the actual type to wrap - */ - public TypeDescriptor(Object value) { - Assert.notNull(value, "Value must not be null"); - this.value = value; - this.type = value.getClass(); - } - // protected constructors for subclasses /** @@ -148,6 +124,30 @@ public class TypeDescriptor { private TypeDescriptor() { } + /** + * Create a new descriptor for the type of the given value. + *

Use this constructor when a conversion point comes from a source such as a Map or + * Collection, where no additional context is available but elements can be introspected. + * @param type the actual type to wrap + */ + private TypeDescriptor(Object value) { + Assert.notNull(value, "Value must not be null"); + this.value = value; + this.type = value.getClass(); + } + + /** + * Create a new descriptor for the given type. + *

Use this constructor when a conversion point comes from a plain source type, + * where no additional context is available. + * @param type the actual type to wrap + */ + private TypeDescriptor(Class type) { + Assert.notNull(type, "Type must not be null"); + this.type = type; + } + + /** * Return the wrapped MethodParameter, if any. *

Note: Either MethodParameter or Field is available. @@ -237,19 +237,14 @@ public class TypeDescriptor { * Return the element type as a type descriptor. */ public TypeDescriptor getElementTypeDescriptor() { - if (this.elementType != null) { - return this.elementType; + if (isArray()) { + return TypeDescriptor.valueOf(getArrayComponentType()); + } + else if (isCollection()) { + return TypeDescriptor.valueOf(getCollectionElementType()); } else { - if (isArray()) { - return TypeDescriptor.valueOf(getArrayComponentType()); - } - else if (isCollection()) { - return TypeDescriptor.valueOf(getCollectionElementType()); - } - else { - return TypeDescriptor.NULL; - } + return TypeDescriptor.NULL; } } @@ -426,30 +421,7 @@ public class TypeDescriptor { return builder.toString(); } } - - // static factory methods - /** - * Creates a new type descriptor for the given class. - * @param type the class - * @return the type descriptor - */ - public static TypeDescriptor valueOf(Class type) { - if (type == null) { - return TypeDescriptor.NULL; - } - TypeDescriptor desc = typeDescriptorCache.get(type); - return desc != null ? desc : new TypeDescriptor(type); - } - - /** - * Creates a new type descriptor for the class of the given object. - * @param object the object - * @return the type descriptor - */ - public static TypeDescriptor forObject(Object object) { - return (object == null ? NULL : valueOf(object.getClass())); - } // internal helpers @@ -486,5 +458,38 @@ public class TypeDescriptor { Class type = getType(); return (type != null && ClassUtils.isAssignable(clazz, type)); } - -} \ No newline at end of file + + + // static factory methods + + /** + * Create a new type descriptor for the given class. + * @param type the class + * @return the type descriptor + */ + public static TypeDescriptor valueOf(Class type) { + if (type == null) { + return TypeDescriptor.NULL; + } + TypeDescriptor desc = typeDescriptorCache.get(type); + return (desc != null ? desc : new TypeDescriptor(type)); + } + + /** + * Create a new type descriptor for the class of the given object. + * @param object the object + * @return the type descriptor + */ + public static TypeDescriptor forObject(Object object) { + if (object == null) { + return NULL; + } + else if (object instanceof Collection || object instanceof Map) { + return new TypeDescriptor(object); + } + else { + return valueOf(object.getClass()); + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/util/ReflectionUtils.java b/org.springframework.core/src/main/java/org/springframework/util/ReflectionUtils.java index 13b2beea7f3..843398c2cf0 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/ReflectionUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/util/ReflectionUtils.java @@ -58,10 +58,8 @@ public abstract class ReflectionUtils { * the supplied name and/or {@link Class type}. Searches all * superclasses up to {@link Object}. * @param clazz the class to introspect - * @param name the name of the field (may be null if type is - * specified) - * @param type the type of the field (may be null if name is - * specified) + * @param name the name of the field (may be null if type is specified) + * @param type the type of the field (may be null if name is specified) * @return the corresponding Field object, or null if not found */ public static Field findField(Class clazz, String name, Class type) { @@ -81,13 +79,11 @@ public abstract class ReflectionUtils { } /** - * Set the field represented by the supplied {@link Field field object} on - * the specified {@link Object target object} to the specified - * value. In accordance with {@link Field#set(Object, Object)} - * semantics, the new value is automatically unwrapped if the underlying - * field has a primitive type. - *

Thrown exceptions are handled via a call to - * {@link #handleReflectionException(Exception)}. + * Set the field represented by the supplied {@link Field field object} on the + * specified {@link Object target object} to the specified value. + * In accordance with {@link Field#set(Object, Object)} semantics, the new value + * is automatically unwrapped if the underlying field has a primitive type. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. * @param field the field to set * @param target the target object on which to set the field * @param value the value to set; may be null @@ -104,12 +100,11 @@ public abstract class ReflectionUtils { } /** - * Get the field represented by the supplied {@link Field field object} on - * the specified {@link Object target object}. In accordance with - * {@link Field#get(Object)} semantics, the returned value is automatically - * wrapped if the underlying field has a primitive type. - *

Thrown exceptions are handled via a call to - * {@link #handleReflectionException(Exception)}. + * Get the field represented by the supplied {@link Field field object} on the + * specified {@link Object target object}. In accordance with {@link Field#get(Object)} + * semantics, the returned value is automatically wrapped if the underlying field + * has a primitive type. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. * @param field the field to get * @param target the target object from which to get the field * @return the field's current value @@ -126,9 +121,8 @@ public abstract class ReflectionUtils { } /** - * Attempt to find a {@link Method} on the supplied class with the supplied - * name and no parameters. Searches all superclasses up to - * Object. + * Attempt to find a {@link Method} on the supplied class with the supplied name + * and no parameters. Searches all superclasses up to Object. *

Returns null if no {@link Method} can be found. * @param clazz the class to introspect * @param name the name of the method @@ -139,14 +133,13 @@ public abstract class ReflectionUtils { } /** - * Attempt to find a {@link Method} on the supplied class with the supplied - * name and parameter types. Searches all superclasses up to - * Object. + * Attempt to find a {@link Method} on the supplied class with the supplied name + * and parameter types. Searches all superclasses up to Object. *

Returns null if no {@link Method} can be found. * @param clazz the class to introspect * @param name the name of the method - * @param paramTypes the parameter types of the method (may be - * null to indicate any signature) + * @param paramTypes the parameter types of the method + * (may be null to indicate any signature) * @return the Method object, or null if none found */ public static Method findMethod(Class clazz, String name, Class... paramTypes) { @@ -167,11 +160,9 @@ public abstract class ReflectionUtils { } /** - * Invoke the specified {@link Method} against the supplied target object - * with no arguments. The target object can be null when - * invoking a static {@link Method}. - *

Thrown exceptions are handled via a call to - * {@link #handleReflectionException}. + * Invoke the specified {@link Method} against the supplied target object with no arguments. + * The target object can be null when invoking a static {@link Method}. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException}. * @param method the method to invoke * @param target the target object to invoke the method on * @return the invocation result, if any @@ -182,11 +173,10 @@ public abstract class ReflectionUtils { } /** - * Invoke the specified {@link Method} against the supplied target object - * with the supplied arguments. The target object can be null - * when invoking a static {@link Method}. - *

Thrown exceptions are handled via a call to - * {@link #handleReflectionException}. + * Invoke the specified {@link Method} against the supplied target object with the + * supplied arguments. The target object can be null when invoking a + * static {@link Method}. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException}. * @param method the method to invoke * @param target the target object to invoke the method on * @param args the invocation arguments (may be null) @@ -548,7 +538,6 @@ public abstract class ReflectionUtils { + "] must be same or subclass as source class [" + src.getClass().getName() + "]"); } doWithFields(src.getClass(), new FieldCallback() { - public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { makeAccessible(field); Object srcValue = field.get(src); 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 553b6452ded..5813b95e23a 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 @@ -16,12 +16,11 @@ package org.springframework.core.convert; +import java.util.List; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertFalse; - -import java.util.List; - import org.junit.Test; /** @@ -53,7 +52,7 @@ public class TypeDescriptorTests { @Test public void buildingArrayTypeDescriptors() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(new int[0].getClass()); + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int[].class); assertTrue(typeDescriptor.isArray()); assertEquals(Integer.TYPE,typeDescriptor.getElementType()); }