null value */
public static final TypeDescriptor NULL = new TypeDescriptor();
+ /** Constant defining a TypeDescriptor for 'unknown type' */
+ public static final TypeDescriptor UNKNOWN = new TypeDescriptor(Object.class);
+
private static final MapUse this constructor when a conversion point comes from a source such as a Map or
* Collection, where no additional context is available but elements can be introspected.
- * @param type the actual type to wrap
+ * @param value the value to determine the actual type from
*/
private TypeDescriptor(Object value) {
Assert.notNull(value, "Value must not be null");
@@ -263,7 +266,7 @@ public class TypeDescriptor {
*/
public TypeDescriptor getElementTypeDescriptor(Object element) {
TypeDescriptor elementType = getElementTypeDescriptor();
- return (elementType != TypeDescriptor.NULL ? elementType : forObject(element));
+ return (elementType != TypeDescriptor.UNKNOWN ? elementType : forObject(element));
}
/**
@@ -306,7 +309,7 @@ public class TypeDescriptor {
*/
public TypeDescriptor getMapKeyTypeDescriptor(Object key) {
TypeDescriptor keyType = getMapKeyTypeDescriptor();
- return keyType != TypeDescriptor.NULL ? keyType : TypeDescriptor.forObject(key);
+ return (keyType != TypeDescriptor.UNKNOWN ? keyType : TypeDescriptor.forObject(key));
}
/**
@@ -335,7 +338,7 @@ public class TypeDescriptor {
*/
public TypeDescriptor getMapValueTypeDescriptor(Object value) {
TypeDescriptor valueType = getMapValueTypeDescriptor();
- return (valueType != TypeDescriptor.NULL ? valueType : TypeDescriptor.forObject(value));
+ return (valueType != TypeDescriptor.UNKNOWN ? valueType : TypeDescriptor.forObject(value));
}
/**
@@ -390,11 +393,8 @@ public class TypeDescriptor {
* @return the type descriptor
*/
public TypeDescriptor forElementType(Class> elementType) {
- if (getType().equals(elementType)) {
- return this;
- }
- else if (elementType == null) {
- return TypeDescriptor.NULL;
+ if (elementType == null) {
+ return TypeDescriptor.UNKNOWN;
}
else if (this.methodParameter != null) {
return new TypeDescriptor(this.methodParameter, elementType);
@@ -408,21 +408,21 @@ public class TypeDescriptor {
}
public boolean equals(Object obj) {
- if (!(obj instanceof TypeDescriptor)) {
- return false;
- }
- TypeDescriptor td = (TypeDescriptor) obj;
- if (this == td) {
+ if (this == obj) {
return true;
}
+ if (!(obj instanceof TypeDescriptor) || obj == TypeDescriptor.NULL) {
+ return false;
+ }
+ TypeDescriptor other = (TypeDescriptor) obj;
boolean annotatedTypeEquals =
- getType().equals(td.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), td.getAnnotations());
+ getType().equals(other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
if (isCollection()) {
- return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getElementType(), td.getElementType());
+ return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
}
else if (isMap()) {
- return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getMapKeyType(), td.getMapKeyType()) &&
- ObjectUtils.nullSafeEquals(getMapValueType(), td.getMapValueType());
+ return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) &&
+ ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
}
else {
return annotatedTypeEquals;
@@ -430,7 +430,7 @@ public class TypeDescriptor {
}
public int hashCode() {
- return getType().hashCode();
+ return (this == TypeDescriptor.NULL ? 0 : getType().hashCode());
}
/**
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 72e1bbf7e68..906bc423e90 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2010 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.
@@ -58,9 +58,14 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
return null;
}
Collection> sourceCollection = (Collection>) source;
+ if (sourceCollection.isEmpty()) {
+ return sourceCollection;
+ }
Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
for (Object sourceElement : sourceCollection) {
- Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor(sourceElement));
+ Object targetElement = this.conversionService.convert(sourceElement,
+ sourceType.getElementTypeDescriptor(sourceElement),
+ targetType.getElementTypeDescriptor(sourceElement));
target.add(targetElement);
}
return target;
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java
index d0e7025b3fd..d5ca3c8da94 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2010 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.
@@ -62,7 +62,8 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
if (i > 0) {
string.append(DELIMITER);
}
- Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(sourceElement), targetType);
+ Object targetElement = this.conversionService.convert(
+ sourceElement, sourceType.getElementTypeDescriptor(sourceElement), targetType);
string.append(targetElement);
i++;
}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java
index b99dcf4c7bf..4bdcabf9007 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2010 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.
@@ -16,7 +16,6 @@
package org.springframework.core.convert.support;
-import java.util.Collection;
import java.util.Map;
import org.springframework.core.convert.ConversionFailedException;
@@ -41,15 +40,6 @@ abstract class ConversionUtils {
}
}
- public static TypeDescriptor getElementType(Collection> collection) {
- for (Object element : collection) {
- if (element != null) {
- return TypeDescriptor.valueOf(element.getClass());
- }
- }
- return TypeDescriptor.NULL;
- }
-
public static TypeDescriptor[] getMapEntryTypes(Map, ?> sourceMap) {
Class> keyType = null;
Class> valueType = null;
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 894dfcd0234..1054aa5d974 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
@@ -244,7 +244,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
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);
@@ -394,6 +394,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
private GenericConverter getMatchingConverterForTarget(TypeDescriptor sourceType, TypeDescriptor targetType,
Map> list = Collections.singletonList(Collections.singletonList("Foo"));
+ assertNotNull(service.convert(list, String.class));
+ }
+
+ @Test
+ public void testEmptyList() {
+ GenericConversionService service = ConversionServiceFactory.createDefaultConversionService();
+ List list = Collections.emptyList();
+ List result = service.convert(list, List.class);
+ assertSame(list, result);
+ result = service.convert(list, list.getClass());
+ assertSame(list, result);
+ }
+
+ @Test
+ public void testEmptyMap() {
+ GenericConversionService service = ConversionServiceFactory.createDefaultConversionService();
+ Map map = Collections.emptyMap();
+ Map result = service.convert(map, Map.class);
+ assertSame(map, result);
+ result = service.convert(map, map.getClass());
+ assertSame(map, result);
+ }
+
+ @Test
+ public void testStringToString() {
+ GenericConversionService service = ConversionServiceFactory.createDefaultConversionService();
+ String value = "myValue";
+ String result = service.convert(value, String.class);
+ assertSame(value, result);
+ }
+
+ @Test
+ public void testStringToObject() {
+ GenericConversionService service = ConversionServiceFactory.createDefaultConversionService();
+ String value = "myValue";
+ Object result = service.convert(value, Object.class);
+ assertSame(value, result);
+ }
+
+ @Test
+ public void testIgnoreCopyConstructor() {
+ GenericConversionService service = ConversionServiceFactory.createDefaultConversionService();
+ WithCopyConstructor value = new WithCopyConstructor();
+ Object result = service.convert(value, WithCopyConstructor.class);
+ assertSame(value, result);
+ }
+
@Test
public void testPerformance1() {
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
@@ -296,6 +348,7 @@ public class GenericConversionServiceTests {
public static Map