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 { @@ -34,20 +34,9 @@ public interface ConversionService {
*/
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.
* The TypeDescriptors provide additional context about the field 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.
* The TypeDescriptors provide additional context about the source and target locations where conversion would occur, often object property locations.
* @param sourceType context about the source type to convert from (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
@ -58,13 +47,22 @@ public interface ConversionService { @@ -58,13 +47,22 @@ public interface ConversionService {
/**
* Convert the source to targetType.
* The TypeDescriptors provide additional context about the field locations where conversion will occur, often object property locations.
* 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 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 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 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)
* @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 sourceType is null but source is not null
* @see TypeDescriptor#forObject(Object)

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

@ -70,7 +70,7 @@ public class TypeDescriptor { @@ -70,7 +70,7 @@ public class TypeDescriptor {
/**
* 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
*/
public TypeDescriptor(MethodParameter methodParameter) {
@ -78,8 +78,8 @@ public class TypeDescriptor { @@ -78,8 +78,8 @@ public class TypeDescriptor {
}
/**
* Create a new type descriptor for a field.
* Use this constructor when a conversion point is a field.
* Create a new type descriptor from a {@link Field}.
* Use this constructor when source or target conversion point is a field.
* @param field the field
*/
public TypeDescriptor(Field field) {
@ -87,8 +87,8 @@ public class TypeDescriptor { @@ -87,8 +87,8 @@ public class TypeDescriptor {
}
/**
* Create a new type descriptor for a bean property.
* Use this constructor when a target conversion point is a property on a Java class.
* Create a new type descriptor from a {@link Property}.
* Use this constructor when a source or target conversion point is a property on a Java class.
* @param property the property
*/
public TypeDescriptor(Property property) {
@ -96,9 +96,9 @@ public class TypeDescriptor { @@ -96,9 +96,9 @@ public class TypeDescriptor {
}
/**
* Create a new type descriptor for the given class.
* 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.
* Generally prefer use of {@link #forObject(Object)} for constructing source type descriptors for source objects.
* Create a new type descriptor from the given type.
* 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 type descriptors from source objects, as it handles the null object case.
* @param type the class
* @return the type descriptor
*/
@ -108,9 +108,10 @@ public class TypeDescriptor { @@ -108,9 +108,10 @@ public class TypeDescriptor {
}
/**
* Create a new type descriptor for a java.util.Collection class.
* Useful for supporting conversion of source Collection objects to other types.
* Serves as an alternative to {@link #forObject(Object)} to be used when you cannot rely on Collection element introspection to resolve the element type.
* Create a new type descriptor from a java.util.Collection type.
* Useful for converting to typed Collections.
* 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 elementType the collection's element type, used to convert collection elements
* @return the collection type descriptor
@ -123,9 +124,10 @@ public class TypeDescriptor { @@ -123,9 +124,10 @@ public class TypeDescriptor {
}
/**
* Create a new type descriptor for a java.util.Map class.
* Useful for supporting the conversion of source Map objects to other types.
* 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.
* Create a new type descriptor from a java.util.Map type.
* Useful for Converting to typed Maps.
* 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 keyType the map's key type, used to convert map keys
* @param valueType the map's value type, used to convert map values
@ -201,16 +203,19 @@ public class TypeDescriptor { @@ -201,16 +203,19 @@ public class TypeDescriptor {
}
/**
* 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}
* The type of the backing class, method parameter, field, or property described by this TypeDescriptor.
* 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() {
return type;
}
/**
* Determine the declared type of the wrapped parameter/field.
* Returns the Object wrapper type if the underlying type is a primitive.
* Variation of {@link #getType()} that accounts for a primitive type by returning its object wrapper type.
* 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() {
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; @@ -32,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
@ -139,14 +140,6 @@ public class GenericConversionService implements ConfigurableConversionService { @@ -139,14 +140,6 @@ public class GenericConversionService implements ConfigurableConversionService {
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) {
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
@ -168,6 +161,14 @@ public class GenericConversionService implements ConfigurableConversionService { @@ -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) {
if (targetType == null) {
throw new IllegalArgumentException("The targetType to convert to cannot be null");
@ -190,6 +191,20 @@ public class GenericConversionService implements ConfigurableConversionService { @@ -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() {
List<String> converterStrings = new ArrayList<String>();
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; @@ -36,6 +36,7 @@ import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.support.DefaultConversionService;
/**
* @author Keith Donald

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

@ -16,7 +16,13 @@ @@ -16,7 +16,13 @@
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.BigInteger;
import java.util.AbstractList;
@ -34,12 +40,9 @@ import java.util.Map; @@ -34,12 +40,9 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
@ -51,7 +54,7 @@ import org.springframework.core.convert.converter.ConverterRegistry; @@ -51,7 +54,7 @@ import org.springframework.core.convert.converter.ConverterRegistry;
*/
public class DefaultConversionTests {
private ConversionService conversionService = new DefaultConversionService();
private DefaultConversionService conversionService = new DefaultConversionService();
@Test
public void testStringToCharacter() {
@ -574,6 +577,16 @@ public class DefaultConversionTests { @@ -574,6 +577,16 @@ public class DefaultConversionTests {
assertEquals(new Integer(2), bar.get(1));
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>();
@ -588,6 +601,16 @@ public class DefaultConversionTests { @@ -588,6 +601,16 @@ public class DefaultConversionTests {
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
public void convertPropertiesToString() {
Properties foo = new Properties();

Loading…
Cancel
Save