revised TypeDescriptor NULL and element/mapKey/mapValue type semantics

This commit is contained in:
Keith Donald
2011-06-05 04:43:18 +00:00
parent a2a4929c14
commit c84cccf06d
42 changed files with 732 additions and 758 deletions

View File

@@ -24,6 +24,9 @@ abstract class AbstractDescriptor {
private final Class<?> type;
public AbstractDescriptor(Class<?> type) {
//if (type == null) {
// throw new IllegalArgumentException("type cannot be null");
//}
this.type = type;
}
@@ -33,31 +36,31 @@ abstract class AbstractDescriptor {
public TypeDescriptor getElementType() {
if (isCollection()) {
Class<?> elementType = wildcard(getCollectionElementClass());
return new TypeDescriptor(nested(elementType, 0));
Class<?> elementType = resolveCollectionElementType();
return elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null;
} else if (isArray()) {
Class<?> elementType = getType().getComponentType();
return new TypeDescriptor(nested(elementType, 0));
} else {
return TypeDescriptor.NULL;
return null;
}
}
public TypeDescriptor getMapKeyType() {
if (isMap()) {
Class<?> keyType = wildcard(getMapKeyClass());
return new TypeDescriptor(nested(keyType, 0));
Class<?> keyType = resolveMapKeyType();
return keyType != null ? new TypeDescriptor(nested(keyType, 0)) : null;
} else {
return TypeDescriptor.NULL;
return null;
}
}
public TypeDescriptor getMapValueType() {
if (isMap()) {
Class<?> valueType = wildcard(getMapValueClass());
return new TypeDescriptor(nested(valueType, 1));
Class<?> valueType = resolveMapValueType();
return valueType != null ? new TypeDescriptor(nested(valueType, 1)) : null;
} else {
return TypeDescriptor.NULL;
return null;
}
}
@@ -65,11 +68,11 @@ abstract class AbstractDescriptor {
public AbstractDescriptor nested() {
if (isCollection()) {
return nested(wildcard(getCollectionElementClass()), 0);
return nested(resolveCollectionElementType(), 0);
} else if (isArray()) {
return nested(getType().getComponentType(), 0);
} else if (isMap()) {
return nested(wildcard(getMapValueClass()), 1);
return nested(resolveMapValueType(), 1);
} else {
throw new IllegalStateException("Not a collection, array, or map: cannot resolve nested value types");
}
@@ -77,30 +80,26 @@ abstract class AbstractDescriptor {
// subclassing hooks
protected abstract Class<?> getCollectionElementClass();
protected abstract Class<?> resolveCollectionElementType();
protected abstract Class<?> getMapKeyClass();
protected abstract Class<?> resolveMapKeyType();
protected abstract Class<?> getMapValueClass();
protected abstract Class<?> resolveMapValueType();
protected abstract AbstractDescriptor nested(Class<?> type, int typeIndex);
// internal helpers
private boolean isCollection() {
return Collection.class.isAssignableFrom(getType());
return getType() != null && Collection.class.isAssignableFrom(getType());
}
private boolean isArray() {
return getType().isArray();
return getType() != null && getType().isArray();
}
private boolean isMap() {
return Map.class.isAssignableFrom(getType());
}
private Class<?> wildcard(Class<?> type) {
return type != null ? type : Object.class;
return getType() != null && Map.class.isAssignableFrom(getType());
}
}

View File

@@ -52,17 +52,17 @@ class BeanPropertyDescriptor extends AbstractDescriptor {
}
@Override
protected Class<?> getCollectionElementClass() {
protected Class<?> resolveCollectionElementType() {
return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
}
@Override
protected Class<?> getMapKeyClass() {
protected Class<?> resolveMapKeyType() {
return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
}
@Override
protected Class<?> getMapValueClass() {
protected Class<?> resolveMapValueType() {
return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
}

View File

@@ -29,18 +29,18 @@ class ClassDescriptor extends AbstractDescriptor {
}
@Override
protected Class<?> getCollectionElementClass() {
return Object.class;
protected Class<?> resolveCollectionElementType() {
return null;
}
@Override
protected Class<?> getMapKeyClass() {
return Object.class;
protected Class<?> resolveMapKeyType() {
return null;
}
@Override
protected Class<?> getMapValueClass() {
return Object.class;
protected Class<?> resolveMapValueType() {
return null;
}
@Override

View File

@@ -1,116 +0,0 @@
/*
* 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.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
class CommonElement {
private final Class<?> type;
private final Object value;
public CommonElement(Class<?> type, Object value) {
this.type = type;
this.value = value;
}
public Class<?> getType() {
return type;
}
public Object getValue() {
return value;
}
public TypeDescriptor toTypeDescriptor() {
if (type == null) {
return TypeDescriptor.NULL;
} else if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
return new TypeDescriptor(type, typeDescriptor(collection));
}
else if (value instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) value;
return new TypeDescriptor(type, typeDescriptor(map.keySet()), typeDescriptor(map.values()));
}
else {
return TypeDescriptor.valueOf(type);
}
}
public static TypeDescriptor typeDescriptor(Collection<?> collection) {
return findCommonElement(collection).toTypeDescriptor();
}
// internal helpers
private static CommonElement findCommonElement(Collection<?> values) {
Class<?> commonType = null;
Object candidate = null;
for (Object value : values) {
if (value != null) {
if (candidate == null) {
commonType = value.getClass();
candidate = value;
} else {
commonType = commonType(commonType, value.getClass());
if (commonType == Object.class) {
return new CommonElement(Object.class, null);
}
}
}
}
return new CommonElement(commonType, candidate);
}
private static Class<?> commonType(Class<?> commonType, Class<?> valueClass) {
Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();
classQueue.addFirst(commonType);
while (!classQueue.isEmpty()) {
Class<?> currentClass = classQueue.removeLast();
if (currentClass.isAssignableFrom(valueClass)) {
return currentClass;
}
Class<?> superClass = currentClass.getSuperclass();
if (superClass != null && superClass != Object.class) {
classQueue.addFirst(currentClass.getSuperclass());
}
for (Class<?> interfaceType : currentClass.getInterfaces()) {
addInterfaceHierarchy(interfaceType, interfaces);
}
}
for (Class<?> interfaceType : interfaces) {
if (interfaceType.isAssignableFrom(valueClass)) {
return interfaceType;
}
}
return Object.class;
}
private static void addInterfaceHierarchy(Class<?> interfaceType, Set<Class<?>> interfaces) {
interfaces.add(interfaceType);
for (Class<?> inheritedInterface : interfaceType.getInterfaces()) {
addInterfaceHierarchy(inheritedInterface, interfaces);
}
}
}

View File

@@ -41,7 +41,7 @@ public interface ConversionService {
* @throws ConversionException if an exception occurred
*/
<T> T convert(Object source, Class<T> targetType);
/**
* Returns true if objects of sourceType can be converted to the targetType.
* The TypeDescriptors provide additional context about the field locations where conversion would occur, often object property locations.

View File

@@ -36,17 +36,17 @@ class FieldDescriptor extends AbstractDescriptor {
}
@Override
protected Class<?> getCollectionElementClass() {
protected Class<?> resolveCollectionElementType() {
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel);
}
@Override
protected Class<?> getMapKeyClass() {
protected Class<?> resolveMapKeyType() {
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel);
}
@Override
protected Class<?> getMapValueClass() {
protected Class<?> resolveMapValueType() {
return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel);
}

View File

@@ -43,17 +43,17 @@ class ParameterDescriptor extends AbstractDescriptor {
}
@Override
protected Class<?> getCollectionElementClass() {
protected Class<?> resolveCollectionElementType() {
return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
}
@Override
protected Class<?> getMapKeyClass() {
protected Class<?> resolveMapKeyType() {
return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
}
@Override
protected Class<?> getMapValueClass() {
protected Class<?> resolveMapValueType() {
return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
}

View File

@@ -38,9 +38,6 @@ public class TypeDescriptor {
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
/** Constant defining a TypeDescriptor for a <code>null</code> value */
public static final TypeDescriptor NULL = new TypeDescriptor();
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
static {
@@ -63,7 +60,6 @@ public class TypeDescriptor {
typeDescriptorCache.put(String.class, new TypeDescriptor(String.class));
}
private final Class<?> type;
private final TypeDescriptor elementType;
@@ -110,9 +106,6 @@ public class TypeDescriptor {
* @return the type descriptor
*/
public static TypeDescriptor valueOf(Class<?> type) {
if (type == null) {
return NULL;
}
TypeDescriptor desc = typeDescriptorCache.get(type);
return (desc != null ? desc : new TypeDescriptor(type));
}
@@ -148,37 +141,6 @@ public class TypeDescriptor {
return new TypeDescriptor(mapType, keyType, valueType);
}
/**
* Create a new type descriptor for an object.
* Use this factory method to introspect a source object's type before asking the conversion system to convert it to some another type.
* Populates nested type descriptors for collection and map objects through object introspection.
* If the provided object is null, returns {@link TypeDescriptor#NULL}.
* If the object is not a collection or map, simply calls {@link #valueOf(Class)}.
* If the object is a collection or map, this factory method will derive nested element or key/value types by introspecting the collection or map.
* The introspection algorithm derives nested element or key/value types by resolving the "common element type" across the collection or map.
* For example, if a Collection contained all java.lang.Integer elements, its element type would be java.lang.Integer.
* If a Collection contained several distinct number types all extending from java.lang.Number, its element type would be java.lang.Number.
* If a Collection contained a String and a java.util.Map element, its element type would be java.io.Serializable.
* @param object the source object
* @return the type descriptor
* @see ConversionService#convert(Object, Class)
*/
public static TypeDescriptor forObject(Object object) {
if (object == null) {
return NULL;
}
if (object instanceof Collection<?>) {
return new TypeDescriptor(object.getClass(), CommonElement.typeDescriptor((Collection<?>) object));
}
else if (object instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) object;
return new TypeDescriptor(map.getClass(), CommonElement.typeDescriptor(map.keySet()), CommonElement.typeDescriptor(map.values()));
}
else {
return valueOf(object.getClass());
}
}
/**
* Creates a type descriptor for a nested type declared within the method parameter.
* For example, if the methodParameter is a List&lt;String&gt; and the nestingLevel is 1, the nested type descriptor will be String.class.
@@ -224,6 +186,10 @@ public class TypeDescriptor {
return nested(new BeanPropertyDescriptor(beanClass, property), nestingLevel);
}
public static TypeDescriptor forObject(Object source) {
return source != null ? valueOf(source.getClass()) : null;
}
/**
* Determine the declared (non-generic) type of the wrapped parameter/field.
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
@@ -237,21 +203,27 @@ public class TypeDescriptor {
* Returns the Object wrapper type if the underlying type is a primitive.
*/
public Class<?> getObjectType() {
return getType() != null ? ClassUtils.resolvePrimitiveIfNecessary(getType()) : null;
return ClassUtils.resolvePrimitiveIfNecessary(getType());
}
public TypeDescriptor narrowType(Object value) {
if (value == null) {
return this;
}
return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations);
}
/**
* Returns the name of this type: the fully qualified class name.
*/
public String getName() {
return getType() != null ? ClassUtils.getQualifiedName(getType()) : null;
return ClassUtils.getQualifiedName(getType());
}
/**
* Is this type a primitive type?
*/
public boolean isPrimitive() {
return getType() != null && getType().isPrimitive();
return getType().isPrimitive();
}
/**
@@ -281,21 +253,19 @@ public class TypeDescriptor {
* @return true if this type is assignable to the target
*/
public boolean isAssignableTo(TypeDescriptor targetType) {
if (this == TypeDescriptor.NULL || targetType == TypeDescriptor.NULL) {
return true;
boolean typesAssignable = targetType.getObjectType().isAssignableFrom(getObjectType());
if (!typesAssignable) {
return false;
}
if (isCollection() && targetType.isCollection() || isArray() && targetType.isArray()) {
return targetType.getType().isAssignableFrom(getType()) &&
getElementTypeDescriptor().isAssignableTo(targetType.getElementTypeDescriptor());
if (isArray() && targetType.isArray()) {
return getElementType().isAssignableTo(targetType.getElementType());
}
else if (isMap() && targetType.isMap()) {
return targetType.getType().isAssignableFrom(getType()) &&
getMapKeyTypeDescriptor().isAssignableTo(targetType.getMapKeyTypeDescriptor()) &&
getMapValueTypeDescriptor().isAssignableTo(targetType.getMapValueTypeDescriptor());
}
else {
return targetType.getObjectType().isAssignableFrom(getObjectType());
if (isCollection() && targetType.isCollection()) {
return collectionElementsAssignable(targetType.getElementType());
} else if (isMap() && targetType.isMap()) {
return mapKeysAssignable(targetType.getMapKeyType()) && mapValuesAssignable(targetType.getMapValueType());
}
return true;
}
// indexable type descriptor operations
@@ -304,53 +274,36 @@ public class TypeDescriptor {
* Is this type a {@link Collection} type?
*/
public boolean isCollection() {
return getType() != null && Collection.class.isAssignableFrom(getType());
return Collection.class.isAssignableFrom(getType());
}
/**
* Is this type an array type?
*/
public boolean isArray() {
return getType() != null && getType().isArray();
return getType().isArray();
}
/**
* If this type is a {@link Collection} or array, returns the underlying element type.
* Returns Object.class if this type is a collection and the element type was not explicitly declared.
* @return the map element type, or <code>null</code> if not a collection or array.
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
* If this type is an array, returns the array's component type.
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
* If the Collection is not parameterized, returns null indicating the element type is not declared.
* @return the array component type or Collection element type, or <code>null</code> if this type is a Collection but its element type is not parameterized.
* @throws IllegalStateException if this type is not a java.util.Collection or Array type
*/
public Class<?> getElementType() {
return getElementTypeDescriptor().getType();
}
/**
* The collection or array element type as a type descriptor.
* Returns TypeDescriptor.valueOf(Object.class) if this type is a collection and the element type is not explicitly declared.
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
*/
public TypeDescriptor getElementTypeDescriptor() {
public TypeDescriptor getElementType() {
if (!isCollection() && !isArray()) {
throw new IllegalStateException("Not a java.util.Collection or Array");
}
return this.elementType;
}
/**
* Returns a copy of this type descriptor that has its elementType populated from the specified Collection.
* This property will be set by calculating the "common element type" of the specified Collection.
* For example, if the collection contains String elements, the returned TypeDescriptor will have its elementType set to String.
* This method is designed to be used when converting values read from Collection fields or method return values that are not parameterized e.g. Collection vs. Collection<String>
* In this scenario the elementType will be Object.class before invoking this method.
* @param colection the collection to derive the elementType from
* @return a new TypeDescriptor with the resolved elementType property
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Collection.
*/
public TypeDescriptor resolveCollectionElementType(Collection<?> collection) {
if (!isCollection()) {
throw new IllegalStateException("Not a java.util.Collection");
}
return new TypeDescriptor(type, CommonElement.typeDescriptor(collection), mapKeyType, mapValueType, annotations);
public TypeDescriptor elementType(Object element) {
if (elementType != null) {
return elementType.narrowType(element);
} else {
return element != null ? new TypeDescriptor(element.getClass(), null, null, null, annotations) : null;
}
}
// map type descriptor operations
@@ -359,71 +312,51 @@ public class TypeDescriptor {
* Is this type a {@link Map} type?
*/
public boolean isMap() {
return getType() != null && Map.class.isAssignableFrom(getType());
return Map.class.isAssignableFrom(getType());
}
/**
* If this type is a {@link Map}, returns the underlying key type.
* Returns Object.class if this type is a map and its key type was not explicitly declared.
* @return the map key type, or <code>null</code> if not a map.
* @throws IllegalStateException if this descriptor is not for a java.util.Map
* If this type is a {@link Map} and its key type is parameterized, returns the map's key type.
* If the Map's key type is not parameterized, returns null indicating the key type is not declared.
* @return the Map key type, or <code>null</code> if this type is a Map but its key type is not parameterized.
* @throws IllegalStateException if this type is not a java.util.Map.
*/
public Class<?> getMapKeyType() {
return getMapKeyTypeDescriptor().getType();
}
/**
* The map key type as a type descriptor.
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the key type is not explicitly declared.
* @throws IllegalStateException if this descriptor is not for a java.util.Map
*/
public TypeDescriptor getMapKeyTypeDescriptor() {
public TypeDescriptor getMapKeyType() {
if (!isMap()) {
throw new IllegalStateException("Not a map");
}
return this.mapKeyType;
}
/**
* If this type is a {@link Map}, returns the underlying value type.
* Returns <code>null</code> if this type is not map.
* Returns Object.class if this type is a map and its value type was not explicitly declared.
* @return the map value type, or <code>null</code> if not a map.
* @throws IllegalStateException if this descriptor is not for a java.util.Map
*/
public Class<?> getMapValueType() {
return getMapValueTypeDescriptor().getType();
public TypeDescriptor mapKeyType(Object mapKey) {
if (mapKeyType != null) {
return mapKeyType.narrowType(mapKey);
} else {
return mapKey != null ? new TypeDescriptor(mapKey.getClass(), null, null, null, annotations) : null;
}
}
/**
* The map value type as a type descriptor.
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the value type is not explicitly declared.
* @throws IllegalStateException if this descriptor is not for a java.util.Map
* If this type is a {@link Map} and its value type is parameterized, returns the map's value type.
* If the Map's value type is not parameterized, returns null indicating the value type is not declared.
* @return the Map value type, or <code>null</code> if this type is a Map but its value type is not parameterized.
* @throws IllegalStateException if this type is not a java.util.Map.
*/
public TypeDescriptor getMapValueTypeDescriptor() {
public TypeDescriptor getMapValueType() {
if (!isMap()) {
throw new IllegalStateException("Not a map");
}
return this.mapValueType;
}
/**
* Returns a copy of this type descriptor that has its mapKeyType and mapValueType properties populated from the specified Map.
* These properties will be set by calculating the "common element type" of the specified Map's keySet and values collection.
* For example, if the Map contains String keys and Integer values, the returned TypeDescriptor will have its mapKeyType set to String and its mapValueType to Integer.
* This method is designed to be used when converting values read from Map fields or method return values that are not parameterized e.g. Map vs. Map<String, Integer>.
* In this scenario the key and value types will be Object.class before invoking this method.
* @param map the map to derive key and value types from
* @return a new TypeDescriptor with the resolved mapKeyType and mapValueType properties
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Map.
*/
public TypeDescriptor resolveMapKeyValueTypes(Map<?, ?> map) {
if (!isMap()) {
throw new IllegalStateException("Not a java.util.Map");
public TypeDescriptor mapValueType(Object mapValue) {
if (mapValueType != null) {
return mapValueType.narrowType(mapValue);
} else {
return mapValue != null ? new TypeDescriptor(mapValue.getClass(), null, null, null, annotations) : null;
}
return new TypeDescriptor(type, elementType, CommonElement.typeDescriptor(map.keySet()), CommonElement.typeDescriptor(map.values()), annotations);
}
// extending Object
public boolean equals(Object obj) {
@@ -450,29 +383,24 @@ public class TypeDescriptor {
}
public int hashCode() {
return (this == TypeDescriptor.NULL ? 0 : getType().hashCode());
return getType().hashCode();
}
public String toString() {
if (this == TypeDescriptor.NULL) {
return "null";
StringBuilder builder = new StringBuilder();
Annotation[] anns = getAnnotations();
for (Annotation ann : anns) {
builder.append("@").append(ann.annotationType().getName()).append(' ');
}
else {
StringBuilder builder = new StringBuilder();
Annotation[] anns = getAnnotations();
for (Annotation ann : anns) {
builder.append("@").append(ann.annotationType().getName()).append(' ');
}
builder.append(ClassUtils.getQualifiedName(getType()));
if (isMap()) {
builder.append("<").append(getMapKeyTypeDescriptor());
builder.append(", ").append(getMapValueTypeDescriptor()).append(">");
}
else if (isCollection()) {
builder.append("<").append(getElementTypeDescriptor()).append(">");
}
return builder.toString();
builder.append(ClassUtils.getQualifiedName(getType()));
if (isMap()) {
builder.append("<").append(wildcard(getMapKeyType()));
builder.append(", ").append(wildcard(getMapValueType())).append(">");
}
else if (isCollection()) {
builder.append("<").append(wildcard(getElementType())).append(">");
}
return builder.toString();
}
// package private
@@ -485,14 +413,6 @@ public class TypeDescriptor {
this.annotations = descriptor.getAnnotations();
}
TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
this(collectionType, elementType, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
}
TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
this(mapType, TypeDescriptor.NULL, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
}
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY;
}
@@ -503,8 +423,12 @@ public class TypeDescriptor {
this(new ClassDescriptor(type));
}
private TypeDescriptor() {
this(null, TypeDescriptor.NULL, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
private TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
this(collectionType, elementType, null, null, EMPTY_ANNOTATION_ARRAY);
}
private TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
}
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType, Annotation[] annotations) {
@@ -515,8 +439,6 @@ public class TypeDescriptor {
this.annotations = annotations;
}
// internal helpers
private static TypeDescriptor nested(AbstractDescriptor descriptor, int nestingLevel) {
for (int i = 0; i < nestingLevel; i++) {
descriptor = descriptor.nested();
@@ -524,4 +446,43 @@ public class TypeDescriptor {
return new TypeDescriptor(descriptor);
}
// internal helpers
private boolean mapKeysAssignable(TypeDescriptor targetKeyType) {
TypeDescriptor keyType = getMapKeyType();
if (targetKeyType == null) {
return true;
}
if (keyType == null) {
return false;
}
return keyType.isAssignableTo(targetKeyType);
}
private boolean collectionElementsAssignable(TypeDescriptor targetElementType) {
TypeDescriptor elementType = getElementType();
if (targetElementType == null) {
return true;
}
if (elementType == null) {
return false;
}
return elementType.isAssignableTo(targetElementType);
}
private boolean mapValuesAssignable(TypeDescriptor targetValueType) {
TypeDescriptor valueType = getMapValueType();
if (targetValueType == null) {
return true;
}
if (valueType == null) {
return false;
}
return valueType.isAssignableTo(targetValueType);
}
private String wildcard(TypeDescriptor nestedType) {
return nestedType != null ? nestedType.toString() : "?";
}
}

View File

@@ -44,10 +44,6 @@ final class ArrayToArrayConverter implements GenericConverter {
return Collections.singleton(new ConvertiblePair(Object[].class, Object[].class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.matches(sourceType, targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
}

View File

@@ -24,7 +24,7 @@ import java.util.Set;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts an Array to a Collection.
@@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class ArrayToCollectionConverter implements ConditionalGenericConverter {
final class ArrayToCollectionConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -48,10 +48,6 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Object[].class, Collection.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
@@ -59,9 +55,7 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
}
int length = Array.getLength(source);
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), length);
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
if (Object.class.equals(targetElementType.getType())) {
if (targetType.getElementType() == null) {
for (int i = 0; i < length; i++) {
Object sourceElement = Array.get(source, i);
target.add(sourceElement);
@@ -69,7 +63,7 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
} else {
for (int i = 0; i < length; i++) {
Object sourceElement = Array.get(source, i);
Object targetElement = this.conversionService.convert(sourceElement, sourceElementType, targetElementType);
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
target.add(targetElement);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.util.ObjectUtils;
/**
@@ -32,7 +32,7 @@ import org.springframework.util.ObjectUtils;
* @author Keith Donald
* @since 3.0
*/
final class ArrayToObjectConverter implements ConditionalGenericConverter {
final class ArrayToObjectConverter implements GenericConverter {
private final CollectionToObjectConverter helperConverter;
@@ -44,10 +44,6 @@ final class ArrayToObjectConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Object[].class, Object.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.matches(sourceType, targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.util.ObjectUtils;
/**
@@ -32,7 +32,7 @@ import org.springframework.util.ObjectUtils;
* @author Keith Donald
* @since 3.0
*/
final class ArrayToStringConverter implements ConditionalGenericConverter {
final class ArrayToStringConverter implements GenericConverter {
private final CollectionToStringConverter helperConverter;
@@ -44,10 +44,6 @@ final class ArrayToStringConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Object[].class, String.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.matches(sourceType, targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
}

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts a Collection to an array.
@@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class CollectionToArrayConverter implements ConditionalGenericConverter {
final class CollectionToArrayConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -48,20 +48,15 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Collection.class, Object[].class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Collection<?> sourceCollection = (Collection<?>) source;
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
Object array = Array.newInstance(targetElementType.getType(), sourceCollection.size());
Object array = Array.newInstance(targetType.getElementType().getType(), sourceCollection.size());
int i = 0;
for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetElementType);
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
Array.set(array, i++, targetElement);
}
return array;

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts from a Collection to another Collection.
@@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class CollectionToCollectionConverter implements ConditionalGenericConverter {
final class CollectionToCollectionConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -48,12 +48,6 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
return Collections.singleton(new ConvertiblePair(Collection.class, Collection.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
return this.conversionService.canConvert(sourceElementType, targetElementType);
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
@@ -61,17 +55,15 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
}
Collection<?> sourceCollection = (Collection<?>) source;
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
if (Object.class.equals(targetElementType.getType())) {
for (Object sourceElement : sourceCollection) {
target.add(sourceElement);
}
if (targetType.getElementType() == null) {
for (Object element : sourceCollection) {
target.add(element);
}
} else {
for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, sourceElementType, targetElementType);
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
target.add(targetElement);
}
}
}
return target;
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts a Collection to an Object by returning the first collection element after converting it to the desired targetType.
@@ -30,7 +30,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class CollectionToObjectConverter implements ConditionalGenericConverter {
final class CollectionToObjectConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -42,10 +42,6 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Collection.class, Object.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
@@ -55,7 +51,7 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter {
return null;
}
Object firstElement = sourceCollection.iterator().next();
return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor(), targetType);
return this.conversionService.convert(firstElement, sourceType.elementType(firstElement), targetType);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts a Collection to a comma-delimited String.
@@ -30,7 +30,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class CollectionToStringConverter implements ConditionalGenericConverter {
final class CollectionToStringConverter implements GenericConverter {
private static final String DELIMITER = ",";
@@ -44,10 +44,6 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Collection.class, String.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
@@ -56,17 +52,17 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
if (sourceCollection.size() == 0) {
return "";
}
StringBuilder string = new StringBuilder();
StringBuilder sb = new StringBuilder();
int i = 0;
for (Object sourceElement : sourceCollection) {
if (i > 0) {
string.append(DELIMITER);
sb.append(DELIMITER);
}
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType);
string.append(targetElement);
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType);
sb.append(targetElement);
i++;
}
return string.toString();
return sb.toString();
}
}

View File

@@ -138,18 +138,16 @@ public class GenericConversionService implements ConfigurableConversionService {
@SuppressWarnings("unchecked")
public <T> T convert(Object source, Class<T> targetType) {
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
}
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
assertNotNull(sourceType, targetType);
if (logger.isTraceEnabled()) {
logger.trace("Checking if I can convert " + sourceType + " to " + targetType);
}
if (sourceType == TypeDescriptor.NULL || targetType == TypeDescriptor.NULL) {
logger.trace("Yes, I can convert");
return true;
}
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
logger.trace("Yes, I can convert");
@@ -162,21 +160,19 @@ public class GenericConversionService implements ConfigurableConversionService {
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
assertNotNull(sourceType, targetType);
if (logger.isDebugEnabled()) {
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
}
if (sourceType == TypeDescriptor.NULL) {
if (sourceType == null) {
Assert.isTrue(source == null, "The source must be [null] if sourceType == [null]");
return handleResult(sourceType, targetType, convertNullSource(sourceType, targetType));
}
if (targetType == TypeDescriptor.NULL) {
logger.debug("Converted to null");
return null;
}
if (source != null && !sourceType.getObjectType().isInstance(source)) {
throw new IllegalArgumentException("The source to convert from must be an instance of " + sourceType + "; instead it was a " + source.getClass().getName());
}
if (logger.isDebugEnabled()) {
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
}
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
return handleResult(sourceType, targetType, ConversionUtils.invokeConverter(converter, source, sourceType, targetType));
@@ -236,30 +232,26 @@ public class GenericConversionService implements ConfigurableConversionService {
if (logger.isTraceEnabled()) {
logger.trace("Matched cached converter " + converter);
}
return (converter != NO_MATCH ? converter : null);
return converter != NO_MATCH ? converter : null;
}
else {
converter = findConverterForClassPair(sourceType, targetType);
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
if (logger.isTraceEnabled()) {
logger.trace("Caching under " + key);
logger.trace("Caching matched Converter under key " + key);
}
this.converterCache.put(key, converter);
return converter;
}
converter = getDefaultConverter(sourceType, targetType);
if (converter != null) {
} else {
if (logger.isTraceEnabled()) {
logger.trace("Caching under " + key);
logger.trace("Caching Converter [NO_MATCH] result under key " + key);
}
this.converterCache.put(key, converter);
return converter;
this.converterCache.put(key, NO_MATCH);
return null;
}
if (logger.isTraceEnabled()) {
logger.trace("Caching NO_MATCH under " + key);
}
this.converterCache.put(key, NO_MATCH);
return null;
}
}
@@ -312,11 +304,6 @@ public class GenericConversionService implements ConfigurableConversionService {
return sourceMap;
}
private void assertNotNull(TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(sourceType, "The sourceType to convert from is required");
Assert.notNull(targetType, "The targetType to convert to is required");
}
private GenericConverter findConverterForClassPair(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceObjectType = sourceType.getObjectType();
if (sourceObjectType.isInterface()) {

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts a Map to another Map.
@@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class MapToMapConverter implements ConditionalGenericConverter {
final class MapToMapConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -48,11 +48,6 @@ final class MapToMapConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Map.class, Map.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()) &&
this.conversionService.canConvert(sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor());
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
@@ -60,24 +55,30 @@ final class MapToMapConverter implements ConditionalGenericConverter {
}
Map<Object, Object> sourceMap = (Map<Object, Object>) source;
Map<Object, Object> targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size());
TypeDescriptor sourceKeyType = sourceType.getMapKeyTypeDescriptor();
TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor();
TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor();
TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor();
if (Object.class.equals(targetKeyType.getType()) && Object.class.equals(targetValueType.getType())) {
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
targetMap.put(entry.getKey(), entry.getValue());
}
} else {
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
Object sourceKey = entry.getKey();
Object sourceValue = entry.getValue();
Object targetKey = this.conversionService.convert(sourceKey, sourceKeyType, targetKeyType);
Object targetValue = this.conversionService.convert(sourceValue, sourceValueType, targetValueType);
targetMap.put(targetKey, targetValue);
}
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
Object sourceKey = entry.getKey();
Object sourceValue = entry.getValue();
Object targetKey = convertKey(sourceKey, sourceType, targetType.getMapKeyType());
Object targetValue = convertValue(sourceValue, sourceType, targetType.getMapValueType());
targetMap.put(targetKey, targetValue);
}
return targetMap;
}
// internal helpers
private Object convertKey(Object sourceKey, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null) {
return sourceKey;
}
return this.conversionService.convert(sourceKey, sourceType.mapKeyType(sourceKey), targetType);
}
private Object convertValue(Object sourceValue, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null) {
return sourceValue;
}
return this.conversionService.convert(sourceValue, sourceType.mapValueType(sourceValue), targetType);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts an Object to a single-element Array containing the Object.
@@ -31,7 +31,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Keith Donald
* @since 3.0
*/
final class ObjectToArrayConverter implements ConditionalGenericConverter {
final class ObjectToArrayConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -43,16 +43,12 @@ final class ObjectToArrayConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Object.class, Object[].class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Object target = Array.newInstance(targetType.getElementType(), 1);
Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementTypeDescriptor());
Object target = Array.newInstance(targetType.getElementType().getType(), 1);
Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
Array.set(target, 0, targetElement);
return target;
}

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
/**
* Converts an Object to a single-element Collection containing the Object.
@@ -33,7 +33,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
* @author Juergen Hoeller
* @since 3.0
*/
final class ObjectToCollectionConverter implements ConditionalGenericConverter {
final class ObjectToCollectionConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -45,22 +45,17 @@ final class ObjectToCollectionConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(Object.class, Collection.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), 1);
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
// Avoid potential recursion....
if (targetElementType.isCollection()) {
if (targetType.getElementType() == null || targetType.getElementType().isCollection()) {
target.add(source);
} else {
target.add(this.conversionService.convert(source, sourceType, targetElementType));
Object singleElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
target.add(singleElement);
}
return target;
}

View File

@@ -48,9 +48,7 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> source = sourceType.getType();
Class<?> target = targetType.getType();
return !source.equals(target) && hasValueOfMethodOrConstructor(target, source);
return !sourceType.equals(targetType) && hasValueOfMethodOrConstructor(targetType.getType(), sourceType.getType());
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
@@ -79,16 +77,16 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
}
public static boolean hasValueOfMethodOrConstructor(Class<?> targetClass, Class<?> sourceClass) {
return getValueOfMethodOn(targetClass, sourceClass) != null || getConstructor(targetClass, sourceClass) != null;
static boolean hasValueOfMethodOrConstructor(Class<?> clazz, Class<?> sourceParameterType) {
return getValueOfMethodOn(clazz, sourceParameterType) != null || getConstructor(clazz, sourceParameterType) != null;
}
private static Method getValueOfMethodOn(Class<?> targetClass, Class<?> sourceClass) {
return ClassUtils.getStaticMethod(targetClass, "valueOf", sourceClass);
private static Method getValueOfMethodOn(Class<?> clazz, Class<?> sourceParameterType) {
return ClassUtils.getStaticMethod(clazz, "valueOf", sourceParameterType);
}
private static Constructor<?> getConstructor(Class<?> targetClass, Class<?> sourceClass) {
return ClassUtils.getConstructorIfAvailable(targetClass, sourceClass);
private static Constructor<?> getConstructor(Class<?> clazz, Class<?> sourceParameterType) {
return ClassUtils.getConstructorIfAvailable(clazz, sourceParameterType);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.util.StringUtils;
/**
@@ -31,7 +31,7 @@ import org.springframework.util.StringUtils;
* @author Keith Donald
* @since 3.0
*/
final class StringToArrayConverter implements ConditionalGenericConverter {
final class StringToArrayConverter implements GenericConverter {
private final ConversionService conversionService;
@@ -43,20 +43,16 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
String string = (String) source;
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
Object target = Array.newInstance(targetType.getElementType(), fields.length);
Object target = Array.newInstance(targetType.getElementType().getType(), fields.length);
for (int i = 0; i < fields.length; i++) {
String sourceElement = fields[i];
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementType());
Array.set(target, i, targetElement);
}
return target;

View File

@@ -45,7 +45,10 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
if (targetType.getElementType() == null) {
return true;
}
return this.conversionService.canConvert(sourceType, targetType.getElementType());
}
@SuppressWarnings("unchecked")
@@ -56,11 +59,17 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
String string = (String) source;
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), fields.length);
for (String sourceElement : fields) {
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
target.add(targetElement);
if (targetType.getElementType() == null) {
for (String field : fields) {
target.add(field.trim());
}
} else {
for (String field : fields) {
Object targetElement = this.conversionService.convert(field.trim(), sourceType, targetType.getElementType());
target.add(targetElement);
}
}
return target;
}
}
}

View File

@@ -28,7 +28,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
@@ -37,7 +36,6 @@ import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
/**
@@ -62,18 +60,6 @@ public class TypeDescriptorTests {
public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
@Test
public void nullTypeDescriptor() {
TypeDescriptor desc = TypeDescriptor.NULL;
assertEquals(false, desc.isMap());
assertEquals(false, desc.isCollection());
assertEquals(false, desc.isArray());
assertEquals(null, desc.getType());
assertEquals(null, desc.getObjectType());
assertEquals(null, desc.getName());
assertEquals(0, desc.getAnnotations().length);
}
@Test
public void parameterPrimitive() throws Exception {
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0));
@@ -121,12 +107,12 @@ public class TypeDescriptorTests {
assertEquals(0, desc.getAnnotations().length);
assertTrue(desc.isCollection());
assertFalse(desc.isArray());
assertEquals(List.class, desc.getElementType());
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor());
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor());
assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor());
assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType());
assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType());
assertEquals(List.class, desc.getElementType().getType());
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementType());
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementType().getElementType());
assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementType().getElementType().getMapValueType());
assertEquals(Integer.class, desc.getElementType().getElementType().getMapKeyType().getType());
assertEquals(Enum.class, desc.getElementType().getElementType().getMapValueType().getType());
assertFalse(desc.isMap());
}
@@ -141,13 +127,12 @@ public class TypeDescriptorTests {
assertEquals(List.class, desc.getType());
assertEquals(List.class, desc.getObjectType());
assertEquals("java.util.List", desc.getName());
assertEquals("java.util.List<java.lang.Object>", desc.toString());
assertEquals("java.util.List<?>", desc.toString());
assertTrue(!desc.isPrimitive());
assertEquals(0, desc.getAnnotations().length);
assertTrue(desc.isCollection());
assertFalse(desc.isArray());
assertEquals(Object.class, desc.getElementType());
assertEquals(TypeDescriptor.valueOf(Object.class), desc.getElementTypeDescriptor());
assertNull(desc.getElementType());
assertFalse(desc.isMap());
}
@@ -167,8 +152,8 @@ public class TypeDescriptorTests {
assertEquals(0, desc.getAnnotations().length);
assertFalse(desc.isCollection());
assertTrue(desc.isArray());
assertEquals(Integer.class, desc.getElementType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
assertEquals(Integer.class, desc.getElementType().getType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
assertFalse(desc.isMap());
}
@@ -189,11 +174,11 @@ public class TypeDescriptorTests {
assertFalse(desc.isCollection());
assertFalse(desc.isArray());
assertTrue(desc.isMap());
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor());
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor());
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType());
assertEquals(List.class, desc.getMapValueTypeDescriptor().getType());
assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueType());
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueType().getElementType());
assertEquals(Integer.class, desc.getMapKeyType().getType());
assertEquals(List.class, desc.getMapValueType().getType());
assertEquals(String.class, desc.getMapValueType().getElementType().getType());
}
public void testParameterMap(Map<Integer, List<String>> map) {
@@ -222,8 +207,8 @@ public class TypeDescriptorTests {
public void propertyComplex() throws Exception {
PropertyDescriptor property = new PropertyDescriptor("complexProperty", getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
//assertEquals(String.class, desc.getMapKeyType());
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementType());
assertEquals(String.class, desc.getMapKeyType().getType());
assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
}
public Map<String, List<List<Integer>>> getComplexProperty() {
@@ -248,7 +233,7 @@ public class TypeDescriptorTests {
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementType());
assertEquals(Integer.class, desc.getElementType().getType());
}
public interface GenericType<T> {
@@ -292,7 +277,7 @@ public class TypeDescriptorTests {
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementType());
assertEquals(Integer.class, desc.getElementType().getType());
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
}
@@ -323,8 +308,8 @@ public class TypeDescriptorTests {
public void property() throws Exception {
PropertyDescriptor property = new PropertyDescriptor("property", getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementType());
assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementType());
assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
assertNotNull(desc.getAnnotation(MethodAnnotation2.class));
assertNotNull(desc.getAnnotation(MethodAnnotation3.class));
@@ -379,8 +364,7 @@ public class TypeDescriptorTests {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString"));
assertFalse(typeDescriptor.isArray());
assertEquals(List.class, typeDescriptor.getType());
assertEquals(String.class, typeDescriptor.getElementType());
// TODO caught shorten these names but it is OK that they are fully qualified for now
assertEquals(String.class, typeDescriptor.getElementType().getType());
assertEquals("java.util.List<java.lang.String>", typeDescriptor.toString());
}
@@ -389,8 +373,8 @@ public class TypeDescriptorTests {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString"));
assertFalse(typeDescriptor.isArray());
assertEquals(List.class, typeDescriptor.getType());
assertEquals(List.class, typeDescriptor.getElementType());
assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementType());
assertEquals(List.class, typeDescriptor.getElementType().getType());
assertEquals(String.class, typeDescriptor.getElementType().getElementType().getType());
assertEquals("java.util.List<java.util.List<java.lang.String>>", typeDescriptor.toString());
}
@@ -399,16 +383,16 @@ public class TypeDescriptorTests {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown"));
assertFalse(typeDescriptor.isArray());
assertEquals(List.class, typeDescriptor.getType());
assertEquals(List.class, typeDescriptor.getElementType());
assertEquals(Object.class, typeDescriptor.getElementTypeDescriptor().getElementType());
assertEquals("java.util.List<java.util.List<java.lang.Object>>", typeDescriptor.toString());
assertEquals(List.class, typeDescriptor.getElementType().getType());
assertNull(typeDescriptor.getElementType().getElementType());
assertEquals("java.util.List<java.util.List<?>>", typeDescriptor.toString());
}
@Test
public void fieldArray() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray"));
assertTrue(typeDescriptor.isArray());
assertEquals(Integer.TYPE,typeDescriptor.getElementType());
assertEquals(Integer.TYPE,typeDescriptor.getElementType().getType());
assertEquals("int[]",typeDescriptor.toString());
}
@@ -418,7 +402,7 @@ public class TypeDescriptorTests {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString"));
assertTrue(typeDescriptor.isArray());
assertEquals(List.class,typeDescriptor.getElementType());
assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementType());
assertEquals(String.class, typeDescriptor.getElementType().getElementType());
assertEquals("java.util.List[]",typeDescriptor.toString());
}
@@ -426,9 +410,9 @@ public class TypeDescriptorTests {
public void fieldComplexTypeDescriptor2() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField"));
assertTrue(typeDescriptor.isMap());
assertEquals(String.class,typeDescriptor.getMapKeyType());
assertEquals(List.class, typeDescriptor.getMapValueType());
assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementType());
assertEquals(String.class,typeDescriptor.getMapKeyType().getType());
assertEquals(List.class, typeDescriptor.getMapValueType().getType());
assertEquals(Integer.class, typeDescriptor.getMapValueType().getElementType().getType());
assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.toString());
}
@@ -438,8 +422,8 @@ public class TypeDescriptorTests {
// TODO: SPR-8394: typeIndex handling not currently supported by fields
TypeDescriptor desc = new TypeDescriptor(getClass().getField("fieldMap"));
assertTrue(desc.isMap());
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementType());
assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementType());
assertEquals(Integer.class, desc.getMapKeyType().getElementType());
assertEquals(Long.class, desc.getMapValueType().getElementType());
}
public Map<List<Integer>, List<Long>> fieldMap;
@@ -488,7 +472,7 @@ public class TypeDescriptorTests {
assertTrue(typeDescriptor.isArray());
assertFalse(typeDescriptor.isCollection());
assertFalse(typeDescriptor.isMap());
assertEquals(Integer.TYPE, typeDescriptor.getElementType());
assertEquals(Integer.TYPE, typeDescriptor.getElementType().getType());
}
@Test
@@ -497,117 +481,19 @@ public class TypeDescriptorTests {
assertTrue(typeDescriptor.isCollection());
assertFalse(typeDescriptor.isArray());
assertFalse(typeDescriptor.isMap());
assertEquals(Object.class, typeDescriptor.getElementType());
assertNull(typeDescriptor.getElementType());
}
@Test
public void forObjectCollection() {
List<String> list = new ArrayList<String>();
list.add("1");
TypeDescriptor desc = TypeDescriptor.forObject(list);
assertEquals(String.class, desc.getElementType());
public void forObject() {
TypeDescriptor desc = TypeDescriptor.forObject("3");
assertEquals(String.class, desc.getType());
}
@Test
public void forObjectCollectionEmpty() {
List<String> list = new ArrayList<String>();
TypeDescriptor desc = TypeDescriptor.forObject(list);
assertNull(desc.getElementType());
}
@Test
public void forObjectCollectionSuperClassCommonType() throws SecurityException, NoSuchFieldException {
List<Number> list = new ArrayList<Number>();
list.add(1);
list.add(2L);
TypeDescriptor desc = TypeDescriptor.forObject(list);
assertEquals(Number.class, desc.getElementType());
}
public List<Long> longs;
@Test
public void forObjectCollectionNoObviousCommonType() {
List<Object> collection = new ArrayList<Object>();
List<String> list = new ArrayList<String>();
list.add("1");
collection.add(list);
Map<String, String> map = new HashMap<String, String>();
collection.add(map);
map.put("1", "2");
TypeDescriptor desc = TypeDescriptor.forObject(collection);
assertEquals(Cloneable.class, desc.getElementType());
}
@Test
public void forObjectCollectionNoCommonType() {
List<Object> collection = new ArrayList<Object>();
collection.add(new Object());
collection.add("1");
TypeDescriptor desc = TypeDescriptor.forObject(collection);
assertEquals(Object.class, desc.getElementType());
}
@Test
public void forObjectCollectionNested() {
List<Object> collection = new ArrayList<Object>();
collection.add(Arrays.asList("1", "2"));
collection.add(Arrays.asList("3", "4"));
TypeDescriptor desc = TypeDescriptor.forObject(collection);
assertEquals(Arrays.asList("foo").getClass(), desc.getElementType());
assertEquals(String.class, desc.getElementTypeDescriptor().getElementType());
}
@Test
public void forObjectMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "2");
TypeDescriptor desc = TypeDescriptor.forObject(map);
assertEquals(String.class, desc.getMapKeyType());
assertEquals(String.class, desc.getMapValueType());
}
@Test
public void forObjectMapEmpty() {
Map<String, String> map = new HashMap<String, String>();
TypeDescriptor desc = TypeDescriptor.forObject(map);
assertNull(desc.getMapKeyType());
assertNull(desc.getMapValueType());
}
@Test
public void forObjectMapCommonSuperClass() {
Map<Number, Number> map = new HashMap<Number, Number>();
map.put(1, 2);
map.put(2L, 3L);
TypeDescriptor desc = TypeDescriptor.forObject(map);
assertEquals(Number.class, desc.getMapKeyType());
assertEquals(Number.class, desc.getMapValueType());
}
@Test
public void forObjectMapNoObviousCommonType() {
Map<Object, Object> map = new HashMap<Object, Object>();
map.put("1", "2");
map.put(2, 2);
TypeDescriptor desc = TypeDescriptor.forObject(map);
assertEquals(Comparable.class, desc.getMapKeyType());
assertEquals(Comparable.class, desc.getMapValueType());
}
@Test
public void forObjectMapNested() {
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
map.put(1, Arrays.asList("1, 2"));
TypeDescriptor desc = TypeDescriptor.forObject(map);
assertEquals(Integer.class, desc.getMapKeyType());
assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementType());
}
@Test
public void nestedMethodParameterType() throws Exception {
TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test1", List.class), 0), 1);
assertEquals(String.class, t1.getType());
public void forObjectNullTypeDescriptor() {
TypeDescriptor desc = TypeDescriptor.forObject(null);
assertNull(desc);
}
@Test
@@ -692,8 +578,8 @@ public class TypeDescriptorTests {
assertEquals(0, desc.getAnnotations().length);
assertTrue(desc.isCollection());
assertFalse(desc.isArray());
assertEquals(Integer.class, desc.getElementType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
assertEquals(Integer.class, desc.getElementType().getType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
assertFalse(desc.isMap());
}
@@ -708,8 +594,8 @@ public class TypeDescriptorTests {
assertEquals(0, desc.getAnnotations().length);
assertTrue(desc.isCollection());
assertFalse(desc.isArray());
assertEquals(List.class, desc.getElementType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor());
assertEquals(List.class, desc.getElementType().getType());
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType().getElementType());
assertFalse(desc.isMap());
}
@@ -725,8 +611,8 @@ public class TypeDescriptorTests {
assertFalse(desc.isCollection());
assertFalse(desc.isArray());
assertTrue(desc.isMap());
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType());
assertEquals(String.class, desc.getMapKeyType().getType());
assertEquals(Integer.class, desc.getMapValueType().getType());
}
@Test
@@ -742,9 +628,9 @@ public class TypeDescriptorTests {
assertFalse(desc.isCollection());
assertFalse(desc.isArray());
assertTrue(desc.isMap());
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType());
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType());
assertEquals(String.class, desc.getMapKeyType().getType());
assertEquals(String.class, desc.getMapValueType().getMapKeyType().getType());
assertEquals(Integer.class, desc.getMapValueType().getMapValueType().getType());
}
@Test

View File

@@ -16,6 +16,7 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.io.ClassPathResource;
@@ -38,7 +39,12 @@ public class CollectionToCollectionConverterTests {
list.add("37");
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarListTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(list, sourceType, targetType);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
@@ -169,7 +175,7 @@ public class CollectionToCollectionConverterTests {
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
}
@Test(expected=ConverterNotFoundException.class)
@Test
public void allNullsNotConvertible() throws Exception {
List<Resource> resources = new ArrayList<Resource>();
resources.add(null);
@@ -180,7 +186,7 @@ public class CollectionToCollectionConverterTests {
public List<String> allNullsNotConvertible;
@Test(expected=ConverterNotFoundException.class)
@Test(expected=ConversionFailedException.class)
public void nothingInCommon() throws Exception {
List<Object> resources = new ArrayList<Object>();
resources.add(new ClassPathResource("test"));

View File

@@ -73,7 +73,7 @@ public class GenericConversionServiceTests {
@Test(expected=IllegalArgumentException.class)
public void convertNotNullSourceNullSourceTypeDescriptor() {
conversionService.convert("3", TypeDescriptor.NULL, TypeDescriptor.valueOf(int.class));
conversionService.convert("3", null, TypeDescriptor.valueOf(int.class));
}
@Test
@@ -124,14 +124,15 @@ public class GenericConversionServiceTests {
assertNull(conversionService.convert(null, Integer.class));
}
@Test(expected=IllegalArgumentException.class)
public void convertNullTargetClass() {
assertNull(conversionService.convert("3", (Class<?>) null));
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
}
@Test
@Test(expected=IllegalArgumentException.class)
public void convertNullTypeDescriptor() {
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
}
@Test(expected=IllegalArgumentException.class)
@@ -186,7 +187,12 @@ public class GenericConversionServiceTests {
@Test
public void genericConverterDelegatingBackToConversionServiceConverterNotFound() {
conversionService.addConverter(new ObjectToArrayConverter(conversionService));
assertFalse(conversionService.canConvert(String.class, Integer[].class));
assertTrue(conversionService.canConvert(String.class, Integer[].class));
try {
conversionService.convert("3,4,5", Integer[].class);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
}
@Test

View File

@@ -12,6 +12,8 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
public class MapToMapConverterTests {
@@ -30,7 +32,12 @@ public class MapToMapConverterTests {
map.put("2", "37");
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
@@ -58,7 +65,19 @@ public class MapToMapConverterTests {
map.put("2", "37");
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("notGenericMapSource"));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
Map<Integer, Integer> result = (Map<Integer, Integer>) conversionService.convert(map, sourceType, targetType);
assertFalse(map.equals(result));
assertEquals((Integer) 9, result.get(1));
assertEquals((Integer) 37, result.get(2));
}
public Map notGenericMapSource;
@@ -70,7 +89,12 @@ public class MapToMapConverterTests {
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@@ -83,8 +107,6 @@ public class MapToMapConverterTests {
public Map<Integer, List<Integer>> collectionMapTarget;
public Map<String, List<String>> sourceCollectionMapTarget;
@Test
public void collectionMapSourceTarget() throws Exception {
Map<String, List<String>> map = new HashMap<String, List<String>>();
@@ -92,7 +114,12 @@ public class MapToMapConverterTests {
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget"));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
} catch (ConversionFailedException e) {
assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@@ -103,6 +130,8 @@ public class MapToMapConverterTests {
assertEquals(Arrays.asList(37, 23), result.get(2));
}
public Map<String, List<String>> sourceCollectionMapTarget;
@Test
public void collectionMapNotGenericTarget() throws Exception {
Map<String, List<String>> map = new HashMap<String, List<String>>();