diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionException.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionException.java index 423b968ed06..90d47803979 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionException.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionException.java @@ -24,6 +24,7 @@ import org.springframework.core.NestedRuntimeException; * @author Keith Donald * @since 3.0 */ +@SuppressWarnings("serial") public abstract class ConversionException extends NestedRuntimeException { /** diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java index 7a16daa39ff..f1880fea86f 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java @@ -25,6 +25,7 @@ import org.springframework.util.ObjectUtils; * @author Juergen Hoeller * @since 3.0 */ +@SuppressWarnings("serial") public final class ConversionFailedException extends ConversionException { private final TypeDescriptor sourceType; 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 0d20faea4e1..edb8600e2a2 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 @@ -138,10 +138,11 @@ public class TypeDescriptor { return NULL; } if (object instanceof Collection) { - return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType((Collection) object)); + return new TypeDescriptor(object.getClass(), findCommonElement((Collection) object)); } else if (object instanceof Map) { - return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType(((Map) object).keySet()), CollectionUtils.findCommonElementType(((Map) object).values())); + Map map = (Map) object; + return new TypeDescriptor(map.getClass(), findCommonElement(map.keySet()), findCommonElement(map.values())); } else { return valueOf(object.getClass()); @@ -341,37 +342,6 @@ public class TypeDescriptor { public MethodParameter getMethodParameter() { return methodParameter; } - - /** - * Create a copy of this nested type descriptor and apply the specific type information from the indexed value, if necessary. - * Used to support collection and map indexing scenarios, where the indexer has a reference to the indexed type descriptor but needs to ensure its type actually represents the indexed object type. - * This is necessary to support type conversion during collection and map binding operations where generic information may not be available. - */ - public TypeDescriptor applyIndexedObject(Object object) { - if (object == null) { - return this; - } - if (isCollection() && Object.class.equals(getElementType())) { - Collection collection = (Collection) object; - if (collection.size() > 0) { - return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType((Collection) object), methodParameter, field, fieldNestingLevel, annotations); - } else { - return this; - } - } - else if (isMap() && Object.class.equals(getMapKeyType()) && Object.class.equals(getMapValueType())) { - Map map = (Map) object; - if (map.size() > 0) { - return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType(((Map) object).keySet()), - CollectionUtils.findCommonElementType(((Map) object).values()), methodParameter, field, fieldNestingLevel, annotations); - } else { - return this; - } - } - else { - return this; - } - } // extending Object @@ -544,6 +514,20 @@ public class TypeDescriptor { methodParameter.increaseNestingLevel(); return methodParameter; } + + private static Object findCommonElement(Collection values) { + Object candidate = null; + for (Object value : values) { + if (value != null) { + if (candidate == null) { + candidate = value; + } else if (candidate.getClass() != value.getClass()) { + return null; + } + } + } + return candidate; + } // internal constructors @@ -555,46 +539,44 @@ public class TypeDescriptor { this.type = type; } - private TypeDescriptor(Class collectionType, Class elementType) { - this.type = collectionType; - if (elementType == null) { - elementType = Object.class; - } - this.elementType = TypeDescriptor.valueOf(elementType); - } - - private TypeDescriptor(Class mapType, Class keyType, Class valueType) { - this.type = mapType; - if (keyType == null) { - keyType = Object.class; - } - if (valueType == null) { - valueType = Object.class; - } - this.mapKeyType = TypeDescriptor.valueOf(keyType); - this.mapValueType = TypeDescriptor.valueOf(valueType); - } - - private TypeDescriptor(Class collectionType, Class elementType, MethodParameter methodParameter, Field field, int fieldNestingLevel, Annotation[] annotations) { - this(collectionType, elementType); - this.methodParameter = methodParameter; - this.field = field; - this.fieldNestingLevel = fieldNestingLevel; - this.annotations = annotations; - } - - private TypeDescriptor(Class mapType, Class keyType, Class valueType, MethodParameter methodParameter, Field field, int fieldNestingLevel, Annotation[] annotations) { - this(mapType, keyType, valueType); - this.methodParameter = methodParameter; - this.field = field; - this.fieldNestingLevel = fieldNestingLevel; - this.annotations = annotations; - } - private TypeDescriptor(Class nestedType, Field field, int nestingLevel) { this.type = nestedType; this.field = field; this.fieldNestingLevel = nestingLevel; } + public TypeDescriptor(Class mapType, Object commonKey, Object commonValue) { + this.type = mapType; + this.mapKeyType = applyIndexedObject(commonKey); + this.mapValueType = applyIndexedObject(commonValue); + } + + public TypeDescriptor(Class collectionType, Object commonElement) { + this.type = collectionType; + this.elementType = applyIndexedObject(commonElement); + } + + private TypeDescriptor applyIndexedObject(Object object) { + if (object == null) { + return TypeDescriptor.valueOf(Object.class); + } + if (object instanceof Collection) { + Collection collection = (Collection) object; + if (collection.size() == 0) { + return TypeDescriptor.valueOf(Object.class); + } + return new TypeDescriptor(object.getClass(), findCommonElement((Collection) object)); + } + else if (object instanceof Map) { + Map map = (Map) object; + if (map.size() == 0) { + return TypeDescriptor.valueOf(Object.class); + } + return new TypeDescriptor(object.getClass(), findCommonElement(map.keySet()), findCommonElement(map.values())); + } + else { + return TypeDescriptor.valueOf(object.getClass()); + } + } + } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java index 5c0b5c96e48..820b0bd855d 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java @@ -52,12 +52,13 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter { return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); } + @SuppressWarnings("unchecked") public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; } int length = Array.getLength(source); - Collection target = CollectionFactory.createCollection(targetType.getType(), length); + Collection target = CollectionFactory.createCollection(targetType.getType(), length); for (int i = 0; i < length; i++) { Object sourceElement = Array.get(source, i); Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java index a677f518bf6..36e084ad951 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java @@ -64,7 +64,7 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter { Object array = Array.newInstance(targetType.getElementType(), sourceCollection.size()); int i = 0; for (Object sourceElement : sourceCollection) { - Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor().applyIndexedObject(sourceElement), targetType.getElementTypeDescriptor()); + Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); Array.set(array, i++, targetElement); } return array; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java index de84a99769f..f59edfc0331 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java @@ -57,14 +57,15 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert return this.conversionService.canConvert(sourceElementType, targetElementType); } + @SuppressWarnings("unchecked") public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; } Collection sourceCollection = (Collection) source; - Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); + Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); for (Object sourceElement : sourceCollection) { - Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor().applyIndexedObject(sourceElement), targetType.getElementTypeDescriptor()); + Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); target.add(targetElement); } return target; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java index acd947be56a..d5785b2df56 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java @@ -59,7 +59,7 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter { return null; } Object firstElement = sourceCollection.iterator().next(); - return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor().applyIndexedObject(firstElement), targetType); + return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor(), targetType); } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java index 1eea0c986aa..466588b6083 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java @@ -16,9 +16,6 @@ package org.springframework.core.convert.support; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.converter.ConverterRegistry; - /** * A specialization of {@link GenericConversionService} configured by default with * converters appropriate for most applications. diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index 5cd7b6019ff..ebb53d77067 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -481,10 +481,10 @@ public class GenericConversionService implements ConversionService, ConverterReg private final ConvertiblePair typeInfo; - private final Converter converter; + private final Converter converter; public ConverterAdapter(ConvertiblePair typeInfo, Converter converter) { - this.converter = converter; + this.converter = (Converter) converter; this.typeInfo = typeInfo; } @@ -511,10 +511,10 @@ public class GenericConversionService implements ConversionService, ConverterReg private final ConvertiblePair typeInfo; - private final ConverterFactory converterFactory; + private final ConverterFactory converterFactory; public ConverterFactoryAdapter(ConvertiblePair typeInfo, ConverterFactory converterFactory) { - this.converterFactory = converterFactory; + this.converterFactory = (ConverterFactory) converterFactory; this.typeInfo = typeInfo; } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java index 1c71cb88448..5748ac60da9 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java @@ -55,6 +55,7 @@ final class MapToMapConverter implements ConditionalGenericConverter { TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor(); if (Object.class.equals(sourceKeyType.getType()) && Object.class.equals(sourceValueType.getType()) || Object.class.equals(targetKeyType.getType()) && Object.class.equals(targetValueType.getType())) { + // catches the empty map case return true; } return this.conversionService.canConvert(sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()) && @@ -78,8 +79,8 @@ final class MapToMapConverter implements ConditionalGenericConverter { for (Map.Entry entry : sourceMap.entrySet()) { Object sourceKey = entry.getKey(); Object sourceValue = entry.getValue(); - Object targetKey = this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor().applyIndexedObject(sourceKey), targetType.getMapKeyTypeDescriptor()); - Object targetValue = this.conversionService.convert(sourceValue, sourceType.getMapValueTypeDescriptor().applyIndexedObject(sourceValue), targetType.getMapValueTypeDescriptor()); + Object targetKey = this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()); + Object targetValue = this.conversionService.convert(sourceValue, sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor()); targetMap.put(targetKey, targetValue); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java index 79204683bec..df70b15a94b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java @@ -49,11 +49,12 @@ final class ObjectToCollectionConverter implements ConditionalGenericConverter { return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor()); } + @SuppressWarnings("unchecked") public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; } - Collection target = CollectionFactory.createCollection(targetType.getType(), 1); + Collection target = CollectionFactory.createCollection(targetType.getType(), 1); TypeDescriptor elementType = targetType.getElementTypeDescriptor(); // Avoid potential recursion... if (!Collection.class.isAssignableFrom(elementType.getType())) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java index 5f6f4d302ad..fb22bd92d9c 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java @@ -44,8 +44,8 @@ import org.springframework.util.ReflectionUtils; final class ObjectToObjectConverter implements ConditionalGenericConverter { public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { - Class source = sourceType.getObjectType(); - Class target = targetType.getObjectType(); + Class source = sourceType.getObjectType(); + Class target = targetType.getObjectType(); return (!source.equals(target) && hasValueOfMethodOrConstructor(target, source)); } 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 1c250547680..007e36f048a 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 @@ -20,11 +20,9 @@ import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.core.GenericCollectionTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.util.ReflectionUtils; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java index 767d495a025..686a62cddb7 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java @@ -48,13 +48,14 @@ final class StringToCollectionConverter implements ConditionalGenericConverter { return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor()); } + @SuppressWarnings("unchecked") public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; } String string = (String) source; String[] fields = StringUtils.commaDelimitedListToStringArray(string); - Collection target = CollectionFactory.createCollection(targetType.getType(), fields.length); + Collection target = CollectionFactory.createCollection(targetType.getType(), fields.length); for (String sourceElement : fields) { Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor()); target.add(targetElement); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java index 1e816dec4ce..62cf4748eae 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java @@ -25,7 +25,7 @@ import org.springframework.core.convert.converter.ConverterFactory; * @author Keith Donald * @since 3.0 */ -@SuppressWarnings("unchecked") +@SuppressWarnings({ "unchecked", "rawtypes" }) final class StringToEnumConverterFactory implements ConverterFactory { public Converter getConverter(Class targetType) { diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index 4facbd5416d..c760a7b3c01 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -93,7 +93,7 @@ public class Indexer extends SpelNodeImpl { Object possiblyConvertedKey = index; possiblyConvertedKey = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor()); Object o = ((Map) targetObject).get(possiblyConvertedKey); - return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor().applyIndexedObject(o)); + return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor()); } if (targetObject == null) { @@ -105,7 +105,7 @@ public class Indexer extends SpelNodeImpl { int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class)); if (targetObject.getClass().isArray()) { Object arrayElement = accessArrayElement(targetObject, idx); - return new TypedValue(arrayElement, targetObjectTypeDescriptor.getElementTypeDescriptor().applyIndexedObject(arrayElement)); + return new TypedValue(arrayElement, targetObjectTypeDescriptor.getElementTypeDescriptor()); } else if (targetObject instanceof Collection) { Collection c = (Collection) targetObject; if (idx >= c.size()) { @@ -116,7 +116,7 @@ public class Indexer extends SpelNodeImpl { int pos = 0; for (Object o : c) { if (pos == idx) { - return new TypedValue(o, targetObjectTypeDescriptor.getElementTypeDescriptor().applyIndexedObject(o)); + return new TypedValue(o, targetObjectTypeDescriptor.getElementTypeDescriptor()); } pos++; }