Browse Source

added convert(Object, TypeDescriptor) convenience method; collection and map tests

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4460 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/merge
Keith Donald 15 years ago
parent
commit
90bb4c2256
  1. 28
      org.springframework.core/src/main/java/org/springframework/core/convert/ConversionService.java
  2. 41
      org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
  3. 31
      org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
  4. 1
      org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java
  5. 33
      org.springframework.core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java

28
org.springframework.core/src/main/java/org/springframework/core/convert/ConversionService.java

@ -34,20 +34,9 @@ public interface ConversionService {
*/ */
boolean canConvert(Class<?> sourceType, Class<?> targetType); boolean canConvert(Class<?> sourceType, Class<?> targetType);
/**
* Convert the source to targetType.
* @param source the source object to convert (may be null)
* @param targetType the target type to convert to (required)
* @return the converted object, an instance of targetType
* @throws ConversionException if an exception occurred
* @throws IllegalArgumentException if targetType is null
*/
<T> T convert(Object source, Class<T> targetType);
/** /**
* Returns true if objects of sourceType can be converted to the 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. * The TypeDescriptors provide additional context about the source and target locations where conversion would occur, often object property locations.
* This flavor of the canConvert operation exists mainly for use by a general purpose data mapping framework, and not for use by user code.
* @param sourceType context about the source type to convert from (required) * @param sourceType context about the source type to convert from (required)
* @param targetType context about the target type to convert to (required) * @param targetType context about the target type to convert to (required)
* @return true if a conversion can be performed between the source and target types, false if not * @return true if a conversion can be performed between the source and target types, false if not
@ -58,13 +47,22 @@ public interface ConversionService {
/** /**
* Convert the source to targetType. * Convert the source to targetType.
* The TypeDescriptors provide additional context about the field locations where conversion will occur, often object property locations. * @param source the source object to convert (may be null)
* This flavor of the convert operation exists mainly for use by a general purpose data mapping framework, and not for use by user code. * @param targetType the target type to convert to (required)
* @return the converted object, an instance of targetType
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is null
*/
<T> T convert(Object source, Class<T> targetType);
/**
* Convert the source to targetType.
* The TypeDescriptors provide additional context about the source and target locations where conversion will occur, often object property locations.
* @param source the source object to convert (may be null) * @param source the source object to convert (may be null)
* @param sourceType context about the source type converting from (may be null if source is null) * @param sourceType context about the source type converting from (may be null if source is null)
* @param targetType context about the target type to convert to (required) * @param targetType context about the target type to convert to (required)
* @return the converted object, an instance of {@link TypeDescriptor#getObjectType() targetType}</code> * @return the converted object, an instance of {@link TypeDescriptor#getObjectType() targetType}</code>
* @throws ConversionException if an exception occurred * @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is null * @throws IllegalArgumentException if targetType is null
* @throws IllegalArgumentException if sourceType is null but source is not null * @throws IllegalArgumentException if sourceType is null but source is not null
* @see TypeDescriptor#forObject(Object) * @see TypeDescriptor#forObject(Object)

41
org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

@ -70,7 +70,7 @@ public class TypeDescriptor {
/** /**
* Create a new type descriptor from a {@link MethodParameter}. * Create a new type descriptor from a {@link MethodParameter}.
* Use this constructor when a conversion point is a constructor parameter, method parameter, or method return value. * Use this constructor when a source or target conversion point is a constructor parameter, method parameter, or method return value.
* @param methodParameter the method parameter * @param methodParameter the method parameter
*/ */
public TypeDescriptor(MethodParameter methodParameter) { public TypeDescriptor(MethodParameter methodParameter) {
@ -78,8 +78,8 @@ public class TypeDescriptor {
} }
/** /**
* Create a new type descriptor for a field. * Create a new type descriptor from a {@link Field}.
* Use this constructor when a conversion point is a field. * Use this constructor when source or target conversion point is a field.
* @param field the field * @param field the field
*/ */
public TypeDescriptor(Field field) { public TypeDescriptor(Field field) {
@ -87,8 +87,8 @@ public class TypeDescriptor {
} }
/** /**
* Create a new type descriptor for a bean property. * Create a new type descriptor from a {@link Property}.
* Use this constructor when a target conversion point is a property on a Java class. * Use this constructor when a source or target conversion point is a property on a Java class.
* @param property the property * @param property the property
*/ */
public TypeDescriptor(Property property) { public TypeDescriptor(Property property) {
@ -96,9 +96,9 @@ public class TypeDescriptor {
} }
/** /**
* Create a new type descriptor for the given class. * Create a new type descriptor from the given type.
* Use this to instruct the conversion system to convert to an object to a specific target type, when no type location such as a method parameter or field is available to provide additional conversion context. * Use this to instruct the conversion system to convert an object to a specific target type, when no type location such as a method parameter or field is available to provide additional conversion context.
* Generally prefer use of {@link #forObject(Object)} for constructing source type descriptors for source objects. * Generally prefer use of {@link #forObject(Object)} for constructing type descriptors from source objects, as it handles the null object case.
* @param type the class * @param type the class
* @return the type descriptor * @return the type descriptor
*/ */
@ -108,9 +108,10 @@ public class TypeDescriptor {
} }
/** /**
* Create a new type descriptor for a java.util.Collection class. * Create a new type descriptor from a java.util.Collection type.
* Useful for supporting conversion of source Collection objects to other types. * Useful for converting to typed Collections.
* Serves as an alternative to {@link #forObject(Object)} to be used when you cannot rely on Collection element introspection to resolve the element type. * For example, a List&lt;String&gt; could be converted to a List&lt;EmailAddress&gt; by converting to a targetType built with this method.
* The method call to construct such a TypeDescriptor would look something like: collection(List.class, TypeDescriptor.valueOf(EmailAddress.class));
* @param collectionType the collection type, which must implement {@link Collection}. * @param collectionType the collection type, which must implement {@link Collection}.
* @param elementType the collection's element type, used to convert collection elements * @param elementType the collection's element type, used to convert collection elements
* @return the collection type descriptor * @return the collection type descriptor
@ -123,9 +124,10 @@ public class TypeDescriptor {
} }
/** /**
* Create a new type descriptor for a java.util.Map class. * Create a new type descriptor from a java.util.Map type.
* Useful for supporting the conversion of source Map objects to other types. * Useful for Converting to typed Maps.
* Serves as an alternative to {@link #forObject(Object)} to be used when you cannot rely on Map entry introspection to resolve the key and value type. * For example, a Map&lt;String, String&gt; could be converted to a Map&lt;Id, EmailAddress&gt; by converting to a targetType built with this method:
* The method call to construct such a TypeDescriptor would look something like: map(Map.class, TypeDescriptor.valueOf(Id.class), TypeDescriptor.valueOf(EmailAddress.class));
* @param mapType the map type, which must implement {@link Map}. * @param mapType the map type, which must implement {@link Map}.
* @param keyType the map's key type, used to convert map keys * @param keyType the map's key type, used to convert map keys
* @param valueType the map's value type, used to convert map values * @param valueType the map's value type, used to convert map values
@ -201,16 +203,19 @@ public class TypeDescriptor {
} }
/** /**
* Determine the declared (non-generic) type of the wrapped parameter/field. * The type of the backing class, method parameter, field, or property described by this TypeDescriptor.
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL} * Returns primitive types as-is.
* See {@link #getObjectType()} for a variation of this operation that resolves primitive types to their corresponding Object types if necessary.
* @return the type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
* @see #getObjectType()
*/ */
public Class<?> getType() { public Class<?> getType() {
return type; return type;
} }
/** /**
* Determine the declared type of the wrapped parameter/field. * Variation of {@link #getType()} that accounts for a primitive type by returning its object wrapper type.
* Returns the Object wrapper type if the underlying type is a primitive. * This is useful for conversion service implementations that wish to normalize to object-based types and not work with primitive types directly.
*/ */
public Class<?> getObjectType() { public Class<?> getObjectType() {
return ClassUtils.resolvePrimitiveIfNecessary(getType()); return ClassUtils.resolvePrimitiveIfNecessary(getType());

31
org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

@ -32,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericTypeResolver; import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.ConverterNotFoundException;
@ -139,14 +140,6 @@ public class GenericConversionService implements ConfigurableConversionService {
return canConvert(sourceType != null ? TypeDescriptor.valueOf(sourceType) : null, TypeDescriptor.valueOf(targetType)); return canConvert(sourceType != null ? TypeDescriptor.valueOf(sourceType) : null, TypeDescriptor.valueOf(targetType));
} }
@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) { public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null) { if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null"); throw new IllegalArgumentException("The targetType to convert to cannot be null");
@ -168,6 +161,14 @@ 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 Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null) { if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null"); throw new IllegalArgumentException("The targetType to convert to cannot be null");
@ -190,6 +191,20 @@ public class GenericConversionService implements ConfigurableConversionService {
} }
} }
/**
* Convenience operation for converting a source object to the specified targetType, where the targetType is a descriptor that provides additional conversion context.
* Simply delegates to {@link #convert(Object, TypeDescriptor, TypeDescriptor)} and encapsulates the construction of the sourceType descriptor using {@link TypeDescriptor#forObject(Object)}.
* @param source the source object
* @param targetType the target type
* @return the converted value
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is null
* @throws IllegalArgumentException if sourceType is null but source is not null
*/
public Object convert(Object source, TypeDescriptor targetType) {
return convert(source, TypeDescriptor.forObject(source), targetType);
}
public String toString() { public String toString() {
List<String> converterStrings = new ArrayList<String>(); List<String> converterStrings = new ArrayList<String>();
for (Map<Class<?>, MatchableConverters> targetConverters : this.converters.values()) { for (Map<Class<?>, MatchableConverters> targetConverters : this.converters.values()) {

1
org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java

@ -36,6 +36,7 @@ import java.util.Map;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.support.DefaultConversionService;
/** /**
* @author Keith Donald * @author Keith Donald

33
org.springframework.core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java

@ -16,7 +16,13 @@
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
import java.awt.*; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import java.awt.Color;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.AbstractList; import java.util.AbstractList;
@ -34,12 +40,9 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
@ -51,7 +54,7 @@ import org.springframework.core.convert.converter.ConverterRegistry;
*/ */
public class DefaultConversionTests { public class DefaultConversionTests {
private ConversionService conversionService = new DefaultConversionService(); private DefaultConversionService conversionService = new DefaultConversionService();
@Test @Test
public void testStringToCharacter() { public void testStringToCharacter() {
@ -574,6 +577,16 @@ public class DefaultConversionTests {
assertEquals(new Integer(2), bar.get(1)); assertEquals(new Integer(2), bar.get(1));
assertEquals(new Integer(3), bar.get(2)); assertEquals(new Integer(3), bar.get(2));
} }
@Test
public void collection() {
List<String> strings = new ArrayList<String>();
strings.add("3");
strings.add("9");
List<Integer> integers = (List<Integer>) conversionService.convert(strings, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)));
assertEquals(new Integer(3), integers.get(0));
assertEquals(new Integer(9), integers.get(1));
}
public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>(); public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>();
@ -588,6 +601,16 @@ public class DefaultConversionTests {
assertEquals(FooEnum.BAZ, map.get(2)); assertEquals(FooEnum.BAZ, map.get(2));
} }
@Test
public void map() {
Map<String, String> strings = new HashMap<String, String>();
strings.put("3", "9");
strings.put("6", "31");
Map<Integer, Integer> integers = (Map<Integer, Integer>) conversionService.convert(strings, TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Integer.class)));
assertEquals(new Integer(9), integers.get(3));
assertEquals(new Integer(31), integers.get(6));
}
@Test @Test
public void convertPropertiesToString() { public void convertPropertiesToString() {
Properties foo = new Properties(); Properties foo = new Properties();

Loading…
Cancel
Save