more converters; since 3.0

This commit is contained in:
Keith Donald 2009-07-12 17:47:33 +00:00
parent 29139dfd1a
commit 1344a6d4d0
41 changed files with 256 additions and 228 deletions

View File

@ -750,6 +750,7 @@ public class GenericBinder implements Binder {
if (cause instanceof SpelEvaluationException if (cause instanceof SpelEvaluationException
&& ((SpelEvaluationException) cause).getMessageCode() == SpelMessage.TYPE_CONVERSION_ERROR) { && ((SpelEvaluationException) cause).getMessageCode() == SpelMessage.TYPE_CONVERSION_ERROR) {
// TODO this could be a ConverterExecutorNotFoundException if no suitable converter was found // TODO this could be a ConverterExecutorNotFoundException if no suitable converter was found
cause.getCause().printStackTrace();
ConversionFailedException failure = (ConversionFailedException) cause.getCause(); ConversionFailedException failure = (ConversionFailedException) cause.getCause();
MessageBuilder builder = new MessageBuilder(messageSource); MessageBuilder builder = new MessageBuilder(messageSource);
builder.code("conversionFailed"); builder.code("conversionFailed");

View File

@ -280,6 +280,29 @@ public class GenericBinderTests {
assertEquals("12345", bean.addresses.get(2).zip); assertEquals("12345", bean.addresses.get(2).zip);
} }
@Test
@Ignore
public void bindToListSingleStringNoListFormatter() {
binder.addBinding("addresses");
//binder.registerFormatter(new GenericCollectionPropertyType(List.class, Address.class), new AddressListFormatter());
Map<String, String> values = new LinkedHashMap<String, String>();
values.put("addresses", "4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
BindingResults results = binder.bind(values);
Assert.assertEquals(3, bean.addresses.size());
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
assertEquals("Melbourne", bean.addresses.get(0).city);
assertEquals("FL", bean.addresses.get(0).state);
assertEquals("35452", bean.addresses.get(0).zip);
assertEquals("1234 Rostock Circle", bean.addresses.get(1).street);
assertEquals("Palm Bay", bean.addresses.get(1).city);
assertEquals("FL", bean.addresses.get(1).state);
assertEquals("32901", bean.addresses.get(1).zip);
assertEquals("1977 Bel Aire Estates", bean.addresses.get(2).street);
assertEquals("Coker", bean.addresses.get(2).city);
assertEquals("AL", bean.addresses.get(2).state);
assertEquals("12345", bean.addresses.get(2).zip);
}
@Test @Test
public void getListAsSingleString() { public void getListAsSingleString() {
binder.addBinding("addresses"); binder.addBinding("addresses");
@ -348,7 +371,6 @@ public class GenericBinderTests {
Map<String, String[]> values = new LinkedHashMap<String, String[]>(); Map<String, String[]> values = new LinkedHashMap<String, String[]>();
values.put("favoriteFoodsByGroup", new String[] { "DAIRY=Milk", "FRUIT=Peaches", "MEAT=Ham" }); values.put("favoriteFoodsByGroup", new String[] { "DAIRY=Milk", "FRUIT=Peaches", "MEAT=Ham" });
BindingResults results = binder.bind(values); BindingResults results = binder.bind(values);
System.out.println(results);
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
@ -363,8 +385,6 @@ public class GenericBinderTests {
values.put("favoriteFoodsByGroup['FRUIT']", "Peaches"); values.put("favoriteFoodsByGroup['FRUIT']", "Peaches");
values.put("favoriteFoodsByGroup['MEAT']", "Ham"); values.put("favoriteFoodsByGroup['MEAT']", "Ham");
BindingResults results = binder.bind(values); BindingResults results = binder.bind(values);
System.out.println(results);
System.out.println(results);
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
@ -377,7 +397,6 @@ public class GenericBinderTests {
Map<String, String> values = new LinkedHashMap<String, String>(); Map<String, String> values = new LinkedHashMap<String, String>();
values.put("favoriteFoodsByGroup", "DAIRY=Milk FRUIT=Peaches MEAT=Ham"); values.put("favoriteFoodsByGroup", "DAIRY=Milk FRUIT=Peaches MEAT=Ham");
BindingResults results = binder.bind(values); BindingResults results = binder.bind(values);
System.out.println(results);
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));

View File

@ -19,8 +19,8 @@ import org.springframework.core.style.StylerUtils;
/** /**
* Thrown when an attempt to execute a type conversion fails. * Thrown when an attempt to execute a type conversion fails.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class ConversionFailedException extends ConvertException { public class ConversionFailedException extends ConvertException {

View File

@ -17,8 +17,8 @@ package org.springframework.core.convert;
/** /**
* Base class for exceptions thrown by the convert system. * Base class for exceptions thrown by the convert system.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public abstract class ConvertException extends RuntimeException { public abstract class ConvertException extends RuntimeException {

View File

@ -17,8 +17,8 @@ package org.springframework.core.convert;
/** /**
* Thrown when a suitable converter could not be found in a conversion service. * Thrown when a suitable converter could not be found in a conversion service.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class ConverterNotFoundException extends ConvertException { public class ConverterNotFoundException extends ConvertException {

View File

@ -20,8 +20,8 @@ package org.springframework.core.convert;
* <p> * <p>
* Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.<br> * Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.<br>
* Call {@link #convert(Object, TypeDescriptor)} to perform a conversion with additional context about the targetType to convert to. * Call {@link #convert(Object, TypeDescriptor)} to perform a conversion with additional context about the targetType to convert to.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public interface TypeConverter { public interface TypeConverter {

View File

@ -25,11 +25,11 @@ import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.util.Assert; import org.springframework.util.Assert;
// TODO doesn't support more than depth of one (eg. Map<String,List<Foo>> or List<String>[])
/** /**
* Context about a type to convert to. * Context about a type to convert to.
* @author Keith Donald * @author Keith Donald
* @author Andy Clement * @author Andy Clement
* @since 3.0
*/ */
public class TypeDescriptor<T> { public class TypeDescriptor<T> {

View File

@ -25,6 +25,7 @@ import org.springframework.core.convert.TypeConverter;
* invoked behind a {@link TypeConverter}. They typically should not be called directly. * invoked behind a {@link TypeConverter}. They typically should not be called directly.
* </p> * </p>
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public interface Converter<S, T> { public interface Converter<S, T> {

View File

@ -18,6 +18,7 @@ package org.springframework.core.convert.converter;
/** /**
* A factory for "ranged" converters that can convert objects from S to subtypes of R. * A factory for "ranged" converters that can convert objects from S to subtypes of R.
* @author Keith Donald * @author Keith Donald
* @since 3.0
* @param <S> The source type converters created by this factory can convert from * @param <S> The source type converters created by this factory can convert from
* @param <R> The target range (or base) type converters created by this factory can convert to; * @param <R> The target range (or base) type converters created by this factory can convert to;
* for example {@link Number} for a set of number subtypes. * for example {@link Number} for a set of number subtypes.

View File

@ -19,9 +19,12 @@ import org.springframework.core.convert.TypeConverter;
/** /**
* A meta interface a Converter may implement to describe what types he can convert between. * A meta interface a Converter may implement to describe what types he can convert between.
* Implementing this interface is required for converters that do not declare their parameterized types S and T and expect to be registered with a {@link TypeConverter}. * Implementing this interface is required when registering converters that do not declare their parameterized types S and T with a {@link TypeConverter}.
* Such Converters are often dynamically created by a {@link ConverterFactory}.
* @author Keith Donald
* @since 3.0
* @see Converter * @see Converter
* @see SuperConverter * @see ConverterFactory
*/ */
public interface ConverterInfo { public interface ConverterInfo {

View File

@ -18,6 +18,7 @@ package org.springframework.core.convert.converter;
/** /**
* For registering converters with a type conversion system. * For registering converters with a type conversion system.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public interface ConverterRegistry { public interface ConverterRegistry {

View File

@ -21,7 +21,9 @@ import org.springframework.core.convert.TypeDescriptor;
/** /**
* Base class for converters that convert to and from collection types (arrays and java.util.Collection types) * Base class for converters that convert to and from collection types (arrays and java.util.Collection types)
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked")
abstract class AbstractCollectionConverter implements ConversionExecutor { abstract class AbstractCollectionConverter implements ConversionExecutor {
private GenericTypeConverter conversionService; private GenericTypeConverter conversionService;

View File

@ -24,9 +24,10 @@ import org.springframework.core.convert.TypeDescriptor;
* Special one-way converter that converts from a source array to a target array. Supports type conversion of the * Special one-way converter that converts from a source array to a target array. Supports type conversion of the
* individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by * individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by
* {@link TypeConverter} implementations. * {@link TypeConverter} implementations.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked")
class ArrayToArray extends AbstractCollectionConverter { class ArrayToArray extends AbstractCollectionConverter {
public ArrayToArray(TypeDescriptor sourceArrayType, TypeDescriptor targetArrayType, GenericTypeConverter conversionService) { public ArrayToArray(TypeDescriptor sourceArrayType, TypeDescriptor targetArrayType, GenericTypeConverter conversionService) {

View File

@ -24,9 +24,10 @@ import org.springframework.core.convert.TypeDescriptor;
* Special converter that converts from a source array to a target collection. Supports the selection of an * Special converter that converts from a source array to a target collection. Supports the selection of an
* "approximate" collection implementation when a target collection interface such as <code>List.class</code> is * "approximate" collection implementation when a target collection interface such as <code>List.class</code> is
* specified. Supports type conversion of array elements when a parameterized target collection type descriptor is provided. * specified. Supports type conversion of array elements when a parameterized target collection type descriptor is provided.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked")
class ArrayToCollection extends AbstractCollectionConverter { class ArrayToCollection extends AbstractCollectionConverter {
public ArrayToCollection(TypeDescriptor sourceArrayType, TypeDescriptor targetCollectionType, public ArrayToCollection(TypeDescriptor sourceArrayType, TypeDescriptor targetCollectionType,
@ -35,9 +36,8 @@ class ArrayToCollection extends AbstractCollectionConverter {
} }
@Override @Override
@SuppressWarnings("unchecked")
protected Object doExecute(Object sourceArray) throws Exception { protected Object doExecute(Object sourceArray) throws Exception {
Class implClass = CollectionConversionUtils.getImpl(getTargetCollectionType()); Class implClass = ConversionUtils.getCollectionImpl((Class<? extends Collection>) getTargetCollectionType());
Collection collection = (Collection) implClass.newInstance(); Collection collection = (Collection) implClass.newInstance();
int length = Array.getLength(sourceArray); int length = Array.getLength(sourceArray);
ConversionExecutor elementConverter = getElementConverter(); ConversionExecutor elementConverter = getElementConverter();

View File

@ -21,10 +21,11 @@ import org.springframework.util.NumberUtils;
/** /**
* Converts from a Character to any JDK-standard Number implementation. * Converts from a Character to any JDK-standard Number implementation.
* * <p>
* Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class * Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class
* delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion. * delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion.
* * @author Keith Donald
* @since 3.0
* @see java.lang.Byte * @see java.lang.Byte
* @see java.lang.Short * @see java.lang.Short
* @see java.lang.Integer * @see java.lang.Integer
@ -34,8 +35,6 @@ import org.springframework.util.NumberUtils;
* @see java.lang.Double * @see java.lang.Double
* @see java.math.BigDecimal * @see java.math.BigDecimal
* @see NumberUtils * @see NumberUtils
*
* @author Keith Donald
*/ */
public class CharacterToNumberFactory implements ConverterFactory<Character, Number> { public class CharacterToNumberFactory implements ConverterFactory<Character, Number> {

View File

@ -23,14 +23,15 @@ import org.springframework.core.convert.TypeDescriptor;
/** /**
* Special converter that converts from target collection to a source array. * Special converter that converts from target collection to a source array.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked")
class CollectionToArray extends AbstractCollectionConverter { class CollectionToArray extends AbstractCollectionConverter {
public CollectionToArray(TypeDescriptor sourceArrayType, TypeDescriptor targetCollectionType, public CollectionToArray(TypeDescriptor sourceCollectionType, TypeDescriptor targetArrayType,
GenericTypeConverter conversionService) { GenericTypeConverter conversionService) {
super(sourceArrayType, targetCollectionType, conversionService); super(sourceCollectionType, targetArrayType, conversionService);
} }
@Override @Override

View File

@ -22,9 +22,10 @@ import org.springframework.core.convert.TypeDescriptor;
/** /**
* A converter that can convert from one collection type to another. * A converter that can convert from one collection type to another.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked")
class CollectionToCollection extends AbstractCollectionConverter { class CollectionToCollection extends AbstractCollectionConverter {
public CollectionToCollection(TypeDescriptor sourceCollectionType, TypeDescriptor targetCollectionType, public CollectionToCollection(TypeDescriptor sourceCollectionType, TypeDescriptor targetCollectionType,
@ -33,10 +34,9 @@ class CollectionToCollection extends AbstractCollectionConverter {
} }
@Override @Override
@SuppressWarnings("unchecked")
protected Object doExecute(Object source) throws Exception { protected Object doExecute(Object source) throws Exception {
Collection sourceCollection = (Collection) source; Collection sourceCollection = (Collection) source;
Class implClass = CollectionConversionUtils.getImpl(getTargetCollectionType()); Class implClass = ConversionUtils.getCollectionImpl((Class<? extends Collection>) getTargetCollectionType());
Collection targetCollection = (Collection) implClass.newInstance(); Collection targetCollection = (Collection) implClass.newInstance();
ConversionExecutor elementConverter = getElementConverter(sourceCollection); ConversionExecutor elementConverter = getElementConverter(sourceCollection);
Iterator it = sourceCollection.iterator(); Iterator it = sourceCollection.iterator();

View File

@ -21,8 +21,8 @@ import org.springframework.core.convert.ConversionFailedException;
* A command parameterized with the information necessary to perform a conversion of a source input to a * A command parameterized with the information necessary to perform a conversion of a source input to a
* target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific * target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific
* converter. * converter.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public interface ConversionExecutor { public interface ConversionExecutor {

View File

@ -15,12 +15,11 @@
*/ */
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
/** /**
* Default implementation of a conversion service. Will automatically register <i>from string</i> converters for * Default implementation of a conversion service. Will automatically register <i>from string</i> converters for
* a number of standard Java types like Class, Number, Boolean and so on. * a number of standard Java types like Class, Number, Boolean and so on.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class DefaultTypeConverter extends GenericTypeConverter { public class DefaultTypeConverter extends GenericTypeConverter {

View File

@ -26,9 +26,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.core.GenericTypeResolver; import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeConverter; import org.springframework.core.convert.TypeConverter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory; import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterInfo; import org.springframework.core.convert.converter.ConverterInfo;
@ -36,9 +36,12 @@ import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default. * Base implementation of a conversion service.
* TODO - object to collection/map converters * Initially empty, e.g. no converters are registered by default.
* @author Keith Donald * @author Keith Donald
* @see #add(Converter)
* @see #add(ConverterFactory)
* @since 3.0
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class GenericTypeConverter implements TypeConverter, ConverterRegistry { public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
@ -69,6 +72,9 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
public void add(Converter converter) { public void add(Converter converter) {
List typeInfo = getRequiredTypeInfo(converter); List typeInfo = getRequiredTypeInfo(converter);
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetType <T> your Converter<S, T> converts between");
}
Class sourceType = (Class) typeInfo.get(0); Class sourceType = (Class) typeInfo.get(0);
Class targetType = (Class) typeInfo.get(1); Class targetType = (Class) typeInfo.get(1);
Map sourceMap = getSourceMap(sourceType); Map sourceMap = getSourceMap(sourceType);
@ -77,6 +83,9 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
public void add(ConverterFactory<?, ?> converterFactory) { public void add(ConverterFactory<?, ?> converterFactory) {
List typeInfo = getRequiredTypeInfo(converterFactory); List typeInfo = getRequiredTypeInfo(converterFactory);
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetType <T> your ConverterFactory<S, T> creates Converters to convert between");
}
Class sourceType = (Class) typeInfo.get(0); Class sourceType = (Class) typeInfo.get(0);
Class targetType = (Class) typeInfo.get(1); Class targetType = (Class) typeInfo.get(1);
Map sourceMap = getSourceMap(sourceType); Map sourceMap = getSourceMap(sourceType);
@ -145,9 +154,9 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
Assert.notNull(sourceClass, "The sourceType to convert from is required"); Assert.notNull(sourceClass, "The sourceType to convert from is required");
Assert.notNull(targetType, "The targetType to convert to is required"); Assert.notNull(targetType, "The targetType to convert to is required");
if (targetType.getType() == null) { if (targetType.getType() == null) {
// TODO for Andy - is this correct way to handle the Null TypedValue?
return NoOpConversionExecutor.INSTANCE; return NoOpConversionExecutor.INSTANCE;
} }
// TODO clean this if/else code up
TypeDescriptor sourceType = TypeDescriptor.valueOf(sourceClass); TypeDescriptor sourceType = TypeDescriptor.valueOf(sourceClass);
if (sourceType.isArray()) { if (sourceType.isArray()) {
if (targetType.isArray()) { if (targetType.isArray()) {
@ -161,16 +170,21 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
return new ArrayToCollection(sourceType, targetType, this); return new ArrayToCollection(sourceType, targetType, this);
} else if (targetType.isMap()) { } else if (targetType.isMap()) {
if (sourceType.getElementType().equals(String.class)) { if (sourceType.getElementType().equals(String.class)) {
// string array to map; with string element values in format foo=bar
return new StringArrayToMap(sourceType, targetType, this); return new StringArrayToMap(sourceType, targetType, this);
} else { } else {
// array to map
return null; return null;
} }
} else {
if (targetType.equals(String.class)) {
// array to string;
return null;
} else { } else {
// array to object // array to object
return null; return null;
} }
} }
}
if (sourceType.isCollection()) { if (sourceType.isCollection()) {
if (targetType.isCollection()) { if (targetType.isCollection()) {
return new CollectionToCollection(sourceType, targetType, this); return new CollectionToCollection(sourceType, targetType, this);
@ -178,31 +192,36 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
return new CollectionToArray(sourceType, targetType, this); return new CollectionToArray(sourceType, targetType, this);
} else if (targetType.isMap()) { } else if (targetType.isMap()) {
if (sourceType.getElementType().equals(String.class)) { if (sourceType.getElementType().equals(String.class)) {
// string collection to map; with string element values in format foo=bar return new StringCollectionToMap(sourceType, targetType, this);
return null;
} else { } else {
// object collection to map
return null; return null;
} }
} else {
if (targetType.equals(String.class)) {
// collection to string;
return null;
} else { } else {
// collection to object // collection to object
return null; return null;
} }
} }
}
if (sourceType.isMap()) { if (sourceType.isMap()) {
if (targetType.isMap()) { if (targetType.isMap()) {
return new MapToMap(sourceType, targetType, this); return new MapToMap(sourceType, targetType, this);
} else if (targetType.isArray()) { } else if (targetType.isArray()) {
if (targetType.getElementType().equals(String.class)) { if (targetType.getElementType().equals(String.class)) {
// map to string array; with string element values in format foo=bar return new MapToStringArray(sourceType, targetType, this);
return null;
} else { } else {
// map to object array
return null; return null;
} }
} else if (targetType.isCollection()) { } else if (targetType.isCollection()) {
if (targetType.getElementType().equals(String.class)) { if (targetType.getElementType().equals(String.class)) {
// map to string collection; with string element values in format foo=bar return new MapToStringCollection(sourceType, targetType, this);
return null;
} else { } else {
// map to object collection
return null; return null;
} }
} else { } else {
@ -211,18 +230,24 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
} }
} }
if (targetType.isArray()) { if (targetType.isArray()) {
// object to array if (sourceType.getType().equals(String.class)) {
return null; return new StringToArray(sourceType, targetType, this);
} else {
return new ObjectToArray(sourceType, targetType, this);
}
} }
if (targetType.isCollection()) { if (targetType.isCollection()) {
// object to collection if (sourceType.getType().equals(String.class)) {
return null; return new StringToCollection(sourceType, targetType, this);
} else {
return new ObjectToCollection(sourceType, targetType, this);
}
} }
if (targetType.isMap()) { if (targetType.isMap()) {
// object to map
if (sourceType.getType().equals(String.class)) { if (sourceType.getType().equals(String.class)) {
return new StringToMap(sourceType, targetType, this); return new StringToMap(sourceType, targetType, this);
} else { } else {
// object to map
return null; return null;
} }
} }
@ -246,41 +271,50 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry {
typeInfo.add(info.getSourceType()); typeInfo.add(info.getSourceType());
typeInfo.add(info.getTargetType()); typeInfo.add(info.getTargetType());
return typeInfo; return typeInfo;
} else {
return getConverterTypeInfo(converter.getClass());
} }
Class classToIntrospect = converter.getClass(); }
private List getConverterTypeInfo(Class converterClass) {
Class classToIntrospect = converterClass;
while (classToIntrospect != null) { while (classToIntrospect != null) {
Type[] genericInterfaces = classToIntrospect.getGenericInterfaces(); Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) { for (Type ifc : ifcs) {
if (genericInterface instanceof ParameterizedType) { if (ifc instanceof ParameterizedType) {
ParameterizedType pInterface = (ParameterizedType) genericInterface; ParameterizedType paramIfc = (ParameterizedType) ifc;
if (Converter.class.isAssignableFrom((Class) pInterface.getRawType()) Type rawType = paramIfc.getRawType();
|| ConverterFactory.class.isAssignableFrom((Class) pInterface.getRawType())) { if (Converter.class.equals(rawType) || ConverterFactory.class.equals(rawType)) {
Class s = getParameterClass(pInterface.getActualTypeArguments()[0], converter.getClass()); List typeInfo = new ArrayList(2);
Class t = getParameterClass(pInterface.getActualTypeArguments()[1], converter.getClass()); Type arg1 = paramIfc.getActualTypeArguments()[0];
typeInfo.add(getParameterClass(s, converter.getClass())); if (arg1 instanceof TypeVariable) {
typeInfo.add(getParameterClass(t, converter.getClass())); arg1 = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg1, converterClass);
break;
} }
if (arg1 instanceof Class) {
typeInfo.add((Class) arg1);
}
Type arg2 = paramIfc.getActualTypeArguments()[1];
if (arg2 instanceof TypeVariable) {
arg2 = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg2, converterClass);
}
if (arg2 instanceof Class) {
typeInfo.add((Class) arg2);
}
if (typeInfo.size() == 2) {
return typeInfo;
}
}
else if (Converter.class.isAssignableFrom((Class) rawType)) {
return getConverterTypeInfo((Class) rawType);
}
}
else if (Converter.class.isAssignableFrom((Class) ifc)) {
return getConverterTypeInfo((Class) ifc);
} }
} }
classToIntrospect = classToIntrospect.getSuperclass(); classToIntrospect = classToIntrospect.getSuperclass();
} }
if (typeInfo.size() != 2) { return null;
throw new IllegalArgumentException("Unable to extract source and target class arguments from Converter ["
+ converter.getClass().getName() + "]; does the Converter specify the <S, T> generic types?");
}
return typeInfo;
}
private Class getParameterClass(Type parameterType, Class converterClass) {
if (parameterType instanceof TypeVariable) {
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable) parameterType, converterClass);
}
if (parameterType instanceof Class) {
return (Class) parameterType;
}
throw new IllegalArgumentException("Unable to obtain the java.lang.Class for parameterType [" + parameterType
+ "] on Converter [" + converterClass.getName() + "]");
} }
private Map getSourceMap(Class sourceType) { private Map getSourceMap(Class sourceType) {

View File

@ -15,11 +15,8 @@
*/ */
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
@ -27,6 +24,7 @@ import org.springframework.core.convert.TypeDescriptor;
/** /**
* Converts from one map to another map, with support for converting individual map elements based on generic type information. * Converts from one map to another map, with support for converting individual map elements based on generic type information.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
class MapToMap implements ConversionExecutor { class MapToMap implements ConversionExecutor {
@ -37,7 +35,7 @@ class MapToMap implements ConversionExecutor {
private GenericTypeConverter conversionService; private GenericTypeConverter conversionService;
private EntryConverter entryConverter; private MapEntryConverter entryConverter;
/** /**
* Creates a new map-to-map converter * Creates a new map-to-map converter
@ -52,23 +50,23 @@ class MapToMap implements ConversionExecutor {
this.entryConverter = createEntryConverter(); this.entryConverter = createEntryConverter();
} }
private EntryConverter createEntryConverter() { private MapEntryConverter createEntryConverter() {
if (sourceType.isMapEntryTypeKnown() && targetType.isMapEntryTypeKnown()) { if (sourceType.isMapEntryTypeKnown() && targetType.isMapEntryTypeKnown()) {
ConversionExecutor keyConverter = conversionService.getConversionExecutor(sourceType.getMapKeyType(), ConversionExecutor keyConverter = conversionService.getConversionExecutor(sourceType.getMapKeyType(),
TypeDescriptor.valueOf(targetType.getMapKeyType())); TypeDescriptor.valueOf(targetType.getMapKeyType()));
ConversionExecutor valueConverter = conversionService.getConversionExecutor(sourceType.getMapValueType(), ConversionExecutor valueConverter = conversionService.getConversionExecutor(sourceType.getMapValueType(),
TypeDescriptor.valueOf(targetType.getMapValueType())); TypeDescriptor.valueOf(targetType.getMapValueType()));
return new EntryConverter(keyConverter, valueConverter); return new MapEntryConverter(keyConverter, valueConverter);
} else { } else {
return EntryConverter.NO_OP_INSTANCE; return MapEntryConverter.NO_OP_INSTANCE;
} }
} }
public Object execute(Object source) throws ConversionFailedException { public Object execute(Object source) throws ConversionFailedException {
try { try {
Map map = (Map) source; Map map = (Map) source;
Map targetMap = (Map) getImpl(targetType.getType()).newInstance(); Map targetMap = (Map) ConversionUtils.getMapImpl(targetType.getType()).newInstance();
EntryConverter converter = getEntryConverter(map); MapEntryConverter converter = getEntryConverter(map);
Iterator<Map.Entry<?, ?>> it = map.entrySet().iterator(); Iterator<Map.Entry<?, ?>> it = map.entrySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
Map.Entry entry = it.next(); Map.Entry entry = it.next();
@ -80,9 +78,9 @@ class MapToMap implements ConversionExecutor {
} }
} }
private EntryConverter getEntryConverter(Map<?, ?> map) { private MapEntryConverter getEntryConverter(Map<?, ?> map) {
EntryConverter entryConverter = this.entryConverter; MapEntryConverter entryConverter = this.entryConverter;
if (entryConverter == EntryConverter.NO_OP_INSTANCE) { if (entryConverter == MapEntryConverter.NO_OP_INSTANCE) {
Class<?> targetKeyType = targetType.getMapKeyType(); Class<?> targetKeyType = targetType.getMapKeyType();
Class<?> targetValueType = targetType.getMapValueType(); Class<?> targetValueType = targetType.getMapValueType();
if (targetKeyType != null && targetValueType != null) { if (targetKeyType != null && targetValueType != null) {
@ -105,59 +103,10 @@ class MapToMap implements ConversionExecutor {
break; break;
} }
} }
entryConverter = new EntryConverter(keyConverter, valueConverter); entryConverter = new MapEntryConverter(keyConverter, valueConverter);
} }
} }
return entryConverter; return entryConverter;
} }
static Class<?> getImpl(Class<?> targetClass) {
if (targetClass.isInterface()) {
if (Map.class.equals(targetClass)) {
return HashMap.class;
} else if (SortedMap.class.equals(targetClass)) {
return TreeMap.class;
} else {
throw new IllegalArgumentException("Unsupported Map interface [" + targetClass.getName() + "]");
}
} else {
return targetClass;
}
}
private static class EntryConverter {
public static final EntryConverter NO_OP_INSTANCE = new EntryConverter();
private ConversionExecutor keyConverter;
private ConversionExecutor valueConverter;
private EntryConverter() {
}
public EntryConverter(ConversionExecutor keyConverter, ConversionExecutor valueConverter) {
this.keyConverter = keyConverter;
this.valueConverter = valueConverter;
}
public Object convertKey(Object key) {
if (keyConverter != null) {
return keyConverter.execute(key);
} else {
return key;
}
}
public Object convertValue(Object value) {
if (valueConverter != null) {
return valueConverter.execute(value);
} else {
return value;
}
}
}
} }

View File

@ -18,18 +18,20 @@ package org.springframework.core.convert.support;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
/** /**
* Conversion executor that does nothing. Access singleton at {@link #INSTANCE}.s * Conversion executor that does nothing.
* Access singleton using {@link #INSTANCE}.
* @since 3.0
*/ */
class NoOpConversionExecutor implements ConversionExecutor { class NoOpConversionExecutor implements ConversionExecutor {
public static final ConversionExecutor INSTANCE = new NoOpConversionExecutor(); public static final ConversionExecutor INSTANCE = new NoOpConversionExecutor();
private NoOpConversionExecutor() {
}
public Object execute(Object source) throws ConversionFailedException { public Object execute(Object source) throws ConversionFailedException {
// does nothing
return source; return source;
} }
private NoOpConversionExecutor() {
}
} }

View File

@ -20,7 +20,7 @@ import org.springframework.util.NumberUtils;
/** /**
* Converts from any JDK-standard Number implementation to a Character. * Converts from any JDK-standard Number implementation to a Character.
* * @author Keith Donald
* @see java.lang.Character * @see java.lang.Character
* @see java.lang.Short * @see java.lang.Short
* @see java.lang.Integer * @see java.lang.Integer
@ -30,8 +30,7 @@ import org.springframework.util.NumberUtils;
* @see java.lang.Double * @see java.lang.Double
* @see java.math.BigDecimal * @see java.math.BigDecimal
* @see NumberUtils * @see NumberUtils
* * @since 3.0
* @author Keith Donald
*/ */
public class NumberToCharacter implements Converter<Number, Character> { public class NumberToCharacter implements Converter<Number, Character> {
public Character convert(Number source) { public Character convert(Number source) {

View File

@ -21,10 +21,10 @@ import org.springframework.util.NumberUtils;
/** /**
* Converts from any JDK-standard Number implementation to any other JDK-standard Number implementation. * Converts from any JDK-standard Number implementation to any other JDK-standard Number implementation.
* * <p>
* Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class * Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class
* delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion. * delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion.
* * @author Keith Donald
* @see java.lang.Byte * @see java.lang.Byte
* @see java.lang.Short * @see java.lang.Short
* @see java.lang.Integer * @see java.lang.Integer
@ -34,8 +34,7 @@ import org.springframework.util.NumberUtils;
* @see java.lang.Double * @see java.lang.Double
* @see java.math.BigDecimal * @see java.math.BigDecimal
* @see NumberUtils * @see NumberUtils
* * @since 3.0
* @author Keith Donald
*/ */
public class NumberToNumberFactory implements ConverterFactory<Number, Number> { public class NumberToNumberFactory implements ConverterFactory<Number, Number> {

View File

@ -1,3 +1,18 @@
/*
* Copyright 2004-2009 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.support; package org.springframework.core.convert.support;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
@ -6,6 +21,7 @@ import org.springframework.core.convert.converter.Converter;
* Simply calls {@link Object#toString()} to convert any object to a string. * Simply calls {@link Object#toString()} to convert any object to a string.
* Used by the {@link DefaultTypeConverter} as a fallback if there are no other explicit to string converters registered. * Used by the {@link DefaultTypeConverter} as a fallback if there are no other explicit to string converters registered.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class ObjectToString implements Converter<Object, String> { public class ObjectToString implements Converter<Object, String> {
public String convert(Object source) { public String convert(Object source) {

View File

@ -23,6 +23,7 @@ import org.springframework.core.style.ToStringCreator;
/** /**
* Default conversion executor implementation for converters. * Default conversion executor implementation for converters.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
class StaticConversionExecutor implements ConversionExecutor { class StaticConversionExecutor implements ConversionExecutor {

View File

@ -15,14 +15,18 @@
*/ */
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
import java.util.HashMap; import java.lang.reflect.Array;
import java.util.Map; import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
/**
* Converts a String array to a Map.
* Each element in the array must be formatted as key=value.
* @author Keith Donald
* @since 3.0
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
class StringArrayToMap implements ConversionExecutor { class StringArrayToMap implements ConversionExecutor {
@ -32,7 +36,7 @@ class StringArrayToMap implements ConversionExecutor {
private GenericTypeConverter conversionService; private GenericTypeConverter conversionService;
private EntryConverter entryConverter; private MapEntryConverter entryConverter;
public StringArrayToMap(TypeDescriptor sourceType, TypeDescriptor targetType, GenericTypeConverter conversionService) { public StringArrayToMap(TypeDescriptor sourceType, TypeDescriptor targetType, GenericTypeConverter conversionService) {
this.sourceType = sourceType; this.sourceType = sourceType;
@ -41,24 +45,25 @@ class StringArrayToMap implements ConversionExecutor {
this.entryConverter = createEntryConverter(); this.entryConverter = createEntryConverter();
} }
private EntryConverter createEntryConverter() { private MapEntryConverter createEntryConverter() {
if (targetType.isMapEntryTypeKnown()) { if (targetType.isMapEntryTypeKnown()) {
ConversionExecutor keyConverter = conversionService.getConversionExecutor(String.class, ConversionExecutor keyConverter = conversionService.getConversionExecutor(String.class,
TypeDescriptor.valueOf(targetType.getMapKeyType())); TypeDescriptor.valueOf(targetType.getMapKeyType()));
ConversionExecutor valueConverter = conversionService.getConversionExecutor(String.class, ConversionExecutor valueConverter = conversionService.getConversionExecutor(String.class,
TypeDescriptor.valueOf(targetType.getMapValueType())); TypeDescriptor.valueOf(targetType.getMapValueType()));
return new EntryConverter(keyConverter, valueConverter); return new MapEntryConverter(keyConverter, valueConverter);
} else { } else {
return EntryConverter.NO_OP_INSTANCE; return MapEntryConverter.NO_OP_INSTANCE;
} }
} }
public Object execute(Object source) throws ConversionFailedException { public Object execute(Object source) throws ConversionFailedException {
try { try {
Map targetMap = (Map) getImpl(targetType.getType()).newInstance(); Map targetMap = (Map) ConversionUtils.getMapImpl(targetType.getType()).newInstance();
String[] array = (String[]) source; int length = Array.getLength(source);
for (String string : array) { for (int i = 0; i < length; i++) {
String[] fields = string.split("="); String property = (String) Array.get(source, i);
String[] fields = property.split("=");
String key = fields[0]; String key = fields[0];
String value = fields[1]; String value = fields[1];
targetMap.put(entryConverter.convertKey(key), entryConverter.convertValue(value)); targetMap.put(entryConverter.convertKey(key), entryConverter.convertValue(value));
@ -69,53 +74,4 @@ class StringArrayToMap implements ConversionExecutor {
} }
} }
static Class<?> getImpl(Class<?> targetClass) {
if (targetClass.isInterface()) {
if (Map.class.equals(targetClass)) {
return HashMap.class;
} else if (SortedMap.class.equals(targetClass)) {
return TreeMap.class;
} else {
throw new IllegalArgumentException("Unsupported Map interface [" + targetClass.getName() + "]");
}
} else {
return targetClass;
}
}
private static class EntryConverter {
public static final EntryConverter NO_OP_INSTANCE = new EntryConverter();
private ConversionExecutor keyConverter;
private ConversionExecutor valueConverter;
private EntryConverter() {
}
public EntryConverter(ConversionExecutor keyConverter, ConversionExecutor valueConverter) {
this.keyConverter = keyConverter;
this.valueConverter = valueConverter;
}
public Object convertKey(Object key) {
if (keyConverter != null) {
return keyConverter.execute(key);
} else {
return key;
}
}
public Object convertValue(Object value) {
if (valueConverter != null) {
return valueConverter.execute(value);
} else {
return value;
}
}
}
} }

View File

@ -21,8 +21,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a BigDecimal using {@link BigDecimal#BigDecimal(String). * Converts a String to a BigDecimal using {@link BigDecimal#BigDecimal(String).
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToBigDecimal implements Converter<String, BigDecimal> { public class StringToBigDecimal implements Converter<String, BigDecimal> {
public BigDecimal convert(String source) { public BigDecimal convert(String source) {

View File

@ -21,8 +21,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a BigInteger using {@link BigInteger#BigInteger(String)}. * Converts a String to a BigInteger using {@link BigInteger#BigInteger(String)}.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToBigInteger implements Converter<String, BigInteger> { public class StringToBigInteger implements Converter<String, BigInteger> {
public BigInteger convert(String source) { public BigInteger convert(String source) {

View File

@ -20,9 +20,9 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts String to a Boolean. The trueString and falseStrings are configurable. * Converts String to a Boolean. The trueString and falseStrings are configurable.
*
* @see #StringToBoolean(String, String)
* @author Keith Donald * @author Keith Donald
* @see #StringToBoolean(String, String)
* @since 3.0
*/ */
public class StringToBoolean implements Converter<String, Boolean> { public class StringToBoolean implements Converter<String, Boolean> {

View File

@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a Byte and back. * Converts a String to a Byte and back.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToByte implements Converter<String, Byte> { public class StringToByte implements Converter<String, Byte> {
public Byte convert(String source) { public Byte convert(String source) {

View File

@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a Character and back. * Converts a String to a Character and back.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToCharacter implements Converter<String, Character> { public class StringToCharacter implements Converter<String, Character> {
public Character convert(String source) { public Character convert(String source) {

View File

@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a Double using {@link Double#valueOf(String)}. * Converts a String to a Double using {@link Double#valueOf(String)}.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToDouble implements Converter<String, Double> { public class StringToDouble implements Converter<String, Double> {
public Double convert(String source) { public Double convert(String source) {

View File

@ -1,8 +1,29 @@
/*
* Copyright 2004-2009 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.support; package org.springframework.core.convert.support;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory; import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterInfo;
/**
* A factory for String to enum converters.
* @author Keith Donald
* @since 3.0
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class StringToEnumFactory implements ConverterFactory<String, Enum> { public class StringToEnumFactory implements ConverterFactory<String, Enum> {
@ -10,7 +31,7 @@ public class StringToEnumFactory implements ConverterFactory<String, Enum> {
return new StringToEnum(targetType); return new StringToEnum(targetType);
} }
class StringToEnum<T extends Enum> implements Converter<String, T> { class StringToEnum<T extends Enum> implements Converter<String, T>, ConverterInfo {
private Class<T> enumType; private Class<T> enumType;
@ -18,6 +39,14 @@ public class StringToEnumFactory implements ConverterFactory<String, Enum> {
this.enumType = enumType; this.enumType = enumType;
} }
public Class<String> getSourceType() {
return String.class;
}
public Class<T> getTargetType() {
return enumType;
}
public T convert(String source) throws Exception { public T convert(String source) throws Exception {
return (T) Enum.valueOf(enumType, source); return (T) Enum.valueOf(enumType, source);
} }

View File

@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to Float using {@link Float#valueOf(String)}. * Converts a String to Float using {@link Float#valueOf(String)}.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToFloat implements Converter<String, Float> { public class StringToFloat implements Converter<String, Float> {
public Float convert(String source) { public Float convert(String source) {

View File

@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to an Integer using {@link Integer#valueOf(String)}. * Converts a String to an Integer using {@link Integer#valueOf(String)}.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToInteger implements Converter<String, Integer> { public class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) { public Integer convert(String source) {

View File

@ -23,6 +23,7 @@ import org.springframework.util.StringUtils;
/** /**
* Converts a String to a Locale using {@link StringUtils#parseLocaleString(String)}. * Converts a String to a Locale using {@link StringUtils#parseLocaleString(String)}.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToLocale implements Converter<String, Locale> { public class StringToLocale implements Converter<String, Locale> {
public Locale convert(String source) { public Locale convert(String source) {

View File

@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a Long using {@link Long#valueOf(String)}. * Converts a String to a Long using {@link Long#valueOf(String)}.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToLong implements Converter<String, Long> { public class StringToLong implements Converter<String, Long> {
public Long convert(String source) { public Long convert(String source) {

View File

@ -18,6 +18,18 @@ package org.springframework.core.convert.support;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
/**
* Converts a String to a map.
* The String should be in the format:
* <pre>
* key=value
* key=value
* key=value
* key=value
* </pre>
* @author Keith Donald
* @since 3.0
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
class StringToMap implements ConversionExecutor { class StringToMap implements ConversionExecutor {

View File

@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter;
/** /**
* Converts a String to a Short using {@link Short#valueOf(String)}. * Converts a String to a Short using {@link Short#valueOf(String)}.
* @author Keith Donald * @author Keith Donald
* @since 3.0
*/ */
public class StringToShort implements Converter<String, Short> { public class StringToShort implements Converter<String, Short> {
public Short convert(String source) { public Short convert(String source) {

View File

@ -219,7 +219,6 @@ public class GenericTypeConverterTests {
public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>(); public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>();
@Test @Test
@Ignore
public void convertMapToMap() throws Exception { public void convertMapToMap() throws Exception {
Map<String, String> foo = new HashMap<String, String>(); Map<String, String> foo = new HashMap<String, String>();
foo.put("1", "BAR"); foo.put("1", "BAR");
@ -231,15 +230,15 @@ public class GenericTypeConverterTests {
assertEquals(map.get(2), FooEnum.BAZ); assertEquals(map.get(2), FooEnum.BAZ);
} }
@Ignore
@Test @Test
public void convertObjectToArray() { public void convertObjectToArray() {
String[] result = (String[]) converter.convert("1,2,3", String[].class); String[] result = (String[]) converter.convert("1,2,3", String[].class);
assertEquals(1, result.length); assertEquals(3, result.length);
assertEquals("1,2,3", result[0]); assertEquals("1", result[0]);
assertEquals("2", result[1]);
assertEquals("3", result[2]);
} }
@Ignore
@Test @Test
public void convertObjectToArrayWithElementConversion() { public void convertObjectToArrayWithElementConversion() {
converter.add(new StringToInteger()); converter.add(new StringToInteger());