From 45c82a61974c9e8ebbdcd0ccc0fcbd423413b6bc Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 25 Mar 2010 15:02:19 +0000 Subject: [PATCH] fixed collection element conversion using ConversionService (SPR-6950) git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3176 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../beans/TypeConverterDelegate.java | 16 ++++--- .../core/convert/TypeDescriptor.java | 48 +++++++++++++++---- .../support/PropertyTypeDescriptor.java | 2 +- 3 files changed, 48 insertions(+), 18 deletions(-) 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 f520d6fb654..650a6bf2972 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 @@ -196,8 +196,9 @@ class TypeConverterDelegate { ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); if (editor == null && conversionService != null && convertedValue != null) { TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue); - if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) { - return (T) conversionService.convert(convertedValue, sourceTypeDesc, typeDescriptor); + TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType); + if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) { + return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc); } } @@ -205,8 +206,8 @@ class TypeConverterDelegate { if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) { if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String && typeDescriptor.getMethodParameter() != null) { - Class elementType = GenericCollectionTypeResolver.getCollectionParameterType(typeDescriptor.getMethodParameter()); - if (elementType != null && Enum.class.isAssignableFrom(elementType)) { + Class elemType = GenericCollectionTypeResolver.getCollectionParameterType(typeDescriptor.getMethodParameter()); + if (elemType != null && Enum.class.isAssignableFrom(elemType)) { convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue); } } @@ -572,7 +573,8 @@ class TypeConverterDelegate { if (methodParam != null) { methodParam.increaseNestingLevel(); } - Object convertedElement = convertIfNecessary(indexedPropertyName, null, element, elementType); + Object convertedElement = convertIfNecessary( + indexedPropertyName, null, element, elementType, typeDescriptor); if (methodParam != null) { methodParam.decreaseNestingLevel(); } @@ -651,11 +653,11 @@ class TypeConverterDelegate { methodParam.increaseNestingLevel(); methodParam.setTypeIndexForCurrentLevel(0); } - Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType); + Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType, typeDescriptor); if (methodParam != null) { methodParam.setTypeIndexForCurrentLevel(1); } - Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType); + Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType, typeDescriptor); if (methodParam != null) { methodParam.decreaseNestingLevel(); } 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 2ac6c7cd1ff..e5108a4ea1e 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 @@ -103,8 +103,6 @@ public class TypeDescriptor { this.field = field; } - // protected constructors for subclasses - /** * Create a new type descriptor from a method or constructor parameter. *

Use this constructor when a target conversion point originates from a method parameter, @@ -112,12 +110,23 @@ public class TypeDescriptor { * @param methodParameter the MethodParameter to wrap * @param type the specific type to expose (may be an array/collection element) */ - protected TypeDescriptor(MethodParameter methodParameter, Class type) { + public TypeDescriptor(MethodParameter methodParameter, Class type) { Assert.notNull(methodParameter, "MethodParameter must not be null"); this.methodParameter = methodParameter; this.type = type; } + /** + * Create a new type descriptor for a field. + * Use this constructor when a target conversion point originates from a field. + * @param field the field to wrap + */ + public TypeDescriptor(Field field, Class type) { + Assert.notNull(field, "Field must not be null"); + this.field = field; + this.type = type; + } + /** * Internal constructor for a NULL descriptor. */ @@ -227,24 +236,43 @@ public class TypeDescriptor { /** * If this type is an array type or {@link Collection} type, returns the underlying element type. - * Returns null if the type is neither an array or collection. + * Returns null if the type is neither an array or collection. */ public Class getElementType() { - return getElementTypeDescriptor().getType(); + if (isArray()) { + return getArrayComponentType(); + } + else if (isCollection()) { + return getCollectionElementType(); + } + else { + return null; + } } /** * Return the element type as a type descriptor. */ public TypeDescriptor getElementTypeDescriptor() { - if (isArray()) { - return TypeDescriptor.valueOf(getArrayComponentType()); + return TypeDescriptor.valueOf(getElementType()); + } + + /** + * Create a copy of this type descriptor, preserving the context information + * but exposing the specified element type (e.g. an array/collection element). + * @param elementType the desired type to expose + * @return the type descriptor + */ + public TypeDescriptor forElementType(Class elementType) { + Assert.notNull(elementType, "Element type must not be null"); + if (getType().equals(elementType)) { + return this; } - else if (isCollection()) { - return TypeDescriptor.valueOf(getCollectionElementType()); + else if (this.methodParameter != null) { + return new TypeDescriptor(this.methodParameter, elementType); } else { - return TypeDescriptor.NULL; + return new TypeDescriptor(this.field, elementType); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java index 7f65be655c1..630579e6a52 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java @@ -58,7 +58,7 @@ public class PropertyTypeDescriptor extends TypeDescriptor { * @param methodParameter the target method parameter * @param type the specific type to expose (may be an array/collection element) */ - public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) { + public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) { super(methodParameter, type); this.propertyDescriptor = propertyDescriptor; }