From 1344a6d4d014bda3c73e156bb692d87993f9c11f Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Sun, 12 Jul 2009 17:47:33 +0000 Subject: [PATCH] more converters; since 3.0 --- .../ui/binding/support/GenericBinder.java | 1 + .../binding/support/GenericBinderTests.java | 27 +++- .../convert/ConversionFailedException.java | 2 +- .../core/convert/ConvertException.java | 2 +- .../convert/ConverterNotFoundException.java | 2 +- .../core/convert/TypeConverter.java | 2 +- .../core/convert/TypeDescriptor.java | 2 +- .../core/convert/converter/Converter.java | 1 + .../convert/converter/ConverterFactory.java | 1 + .../core/convert/converter/ConverterInfo.java | 7 +- .../convert/converter/ConverterRegistry.java | 1 + .../support/AbstractCollectionConverter.java | 2 + .../core/convert/support/ArrayToArray.java | 3 +- .../convert/support/ArrayToCollection.java | 6 +- .../support/CharacterToNumberFactory.java | 9 +- .../convert/support/CollectionToArray.java | 7 +- .../support/CollectionToCollection.java | 6 +- .../convert/support/ConversionExecutor.java | 2 +- .../convert/support/DefaultTypeConverter.java | 3 +- .../convert/support/GenericTypeConverter.java | 132 +++++++++++------- .../core/convert/support/MapToMap.java | 75 ++-------- .../support/NoOpConversionExecutor.java | 12 +- .../convert/support/NumberToCharacter.java | 5 +- .../support/NumberToNumberFactory.java | 7 +- .../core/convert/support/ObjectToString.java | 16 +++ .../support/StaticConversionExecutor.java | 1 + .../convert/support/StringArrayToMap.java | 76 +++------- .../convert/support/StringToBigDecimal.java | 2 +- .../convert/support/StringToBigInteger.java | 2 +- .../core/convert/support/StringToBoolean.java | 4 +- .../core/convert/support/StringToByte.java | 2 +- .../convert/support/StringToCharacter.java | 2 +- .../core/convert/support/StringToDouble.java | 2 +- .../convert/support/StringToEnumFactory.java | 33 ++++- .../core/convert/support/StringToFloat.java | 2 +- .../core/convert/support/StringToInteger.java | 1 + .../core/convert/support/StringToLocale.java | 1 + .../core/convert/support/StringToLong.java | 1 + .../core/convert/support/StringToMap.java | 12 ++ .../core/convert/support/StringToShort.java | 1 + .../support/GenericTypeConverterTests.java | 9 +- 41 files changed, 256 insertions(+), 228 deletions(-) diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java index 48a759ce02b..ee7845c7211 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java @@ -750,6 +750,7 @@ public class GenericBinder implements Binder { if (cause instanceof SpelEvaluationException && ((SpelEvaluationException) cause).getMessageCode() == SpelMessage.TYPE_CONVERSION_ERROR) { // TODO this could be a ConverterExecutorNotFoundException if no suitable converter was found + cause.getCause().printStackTrace(); ConversionFailedException failure = (ConversionFailedException) cause.getCause(); MessageBuilder builder = new MessageBuilder(messageSource); builder.code("conversionFailed"); diff --git a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java index 2392d2725af..816a23a13f1 100644 --- a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java @@ -280,6 +280,29 @@ public class GenericBinderTests { 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 values = new LinkedHashMap(); + 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 public void getListAsSingleString() { binder.addBinding("addresses"); @@ -348,7 +371,6 @@ public class GenericBinderTests { Map values = new LinkedHashMap(); values.put("favoriteFoodsByGroup", new String[] { "DAIRY=Milk", "FRUIT=Peaches", "MEAT=Ham" }); BindingResults results = binder.bind(values); - System.out.println(results); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); @@ -363,8 +385,6 @@ public class GenericBinderTests { values.put("favoriteFoodsByGroup['FRUIT']", "Peaches"); values.put("favoriteFoodsByGroup['MEAT']", "Ham"); BindingResults results = binder.bind(values); - System.out.println(results); - System.out.println(results); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); @@ -377,7 +397,6 @@ public class GenericBinderTests { Map values = new LinkedHashMap(); values.put("favoriteFoodsByGroup", "DAIRY=Milk FRUIT=Peaches MEAT=Ham"); BindingResults results = binder.bind(values); - System.out.println(results); Assert.assertEquals(3, bean.favoriteFoodsByGroup.size()); assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY)); assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT)); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java index e821be4b8e1..e0e3ae61e97 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java @@ -19,8 +19,8 @@ import org.springframework.core.style.StylerUtils; /** * Thrown when an attempt to execute a type conversion fails. - * * @author Keith Donald + * @since 3.0 */ public class ConversionFailedException extends ConvertException { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ConvertException.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ConvertException.java index f1bd2188145..a05ee34e5c8 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/ConvertException.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ConvertException.java @@ -17,8 +17,8 @@ package org.springframework.core.convert; /** * Base class for exceptions thrown by the convert system. - * * @author Keith Donald + * @since 3.0 */ public abstract class ConvertException extends RuntimeException { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java index 41f1c306e8c..5e86f273761 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java @@ -17,8 +17,8 @@ package org.springframework.core.convert; /** * Thrown when a suitable converter could not be found in a conversion service. - * * @author Keith Donald + * @since 3.0 */ public class ConverterNotFoundException extends ConvertException { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeConverter.java index 386a2e39e76..8a7150fbd54 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeConverter.java @@ -20,8 +20,8 @@ package org.springframework.core.convert; *

* Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.
* Call {@link #convert(Object, TypeDescriptor)} to perform a conversion with additional context about the targetType to convert to. - * * @author Keith Donald + * @since 3.0 */ public interface TypeConverter { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index e260f5fd9e0..123adc1712a 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -25,11 +25,11 @@ import org.springframework.core.GenericCollectionTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; -// TODO doesn't support more than depth of one (eg. Map> or List[]) /** * Context about a type to convert to. * @author Keith Donald * @author Andy Clement + * @since 3.0 */ public class TypeDescriptor { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/Converter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/Converter.java index 252a6af7f63..e9e5823a42a 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/Converter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/Converter.java @@ -25,6 +25,7 @@ import org.springframework.core.convert.TypeConverter; * invoked behind a {@link TypeConverter}. They typically should not be called directly. *

* @author Keith Donald + * @since 3.0 */ public interface Converter { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java index 4753c6e0b42..9b6ebb9cc74 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java @@ -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. * @author Keith Donald + * @since 3.0 * @param The source type converters created by this factory can convert from * @param The target range (or base) type converters created by this factory can convert to; * for example {@link Number} for a set of number subtypes. diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterInfo.java b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterInfo.java index 6824b11690b..4e4029bc48b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterInfo.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterInfo.java @@ -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. - * 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 SuperConverter + * @see ConverterFactory */ public interface ConverterInfo { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterRegistry.java b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterRegistry.java index 32c0da7c687..bd676427e41 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterRegistry.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/converter/ConverterRegistry.java @@ -18,6 +18,7 @@ package org.springframework.core.convert.converter; /** * For registering converters with a type conversion system. * @author Keith Donald + * @since 3.0 */ public interface ConverterRegistry { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/AbstractCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/AbstractCollectionConverter.java index 431d575d8ee..a12824079ab 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/AbstractCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/AbstractCollectionConverter.java @@ -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) * @author Keith Donald + * @since 3.0 */ +@SuppressWarnings("unchecked") abstract class AbstractCollectionConverter implements ConversionExecutor { private GenericTypeConverter conversionService; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArray.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArray.java index bea0cbf9182..4aa4d4b7f2d 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArray.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArray.java @@ -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 * individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by * {@link TypeConverter} implementations. - * * @author Keith Donald + * @since 3.0 */ +@SuppressWarnings("unchecked") class ArrayToArray extends AbstractCollectionConverter { public ArrayToArray(TypeDescriptor sourceArrayType, TypeDescriptor targetArrayType, GenericTypeConverter conversionService) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollection.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollection.java index d9510d184f5..fffeefe2178 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollection.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollection.java @@ -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 * "approximate" collection implementation when a target collection interface such as List.class is * specified. Supports type conversion of array elements when a parameterized target collection type descriptor is provided. - * * @author Keith Donald + * @since 3.0 */ +@SuppressWarnings("unchecked") class ArrayToCollection extends AbstractCollectionConverter { public ArrayToCollection(TypeDescriptor sourceArrayType, TypeDescriptor targetCollectionType, @@ -35,9 +36,8 @@ class ArrayToCollection extends AbstractCollectionConverter { } @Override - @SuppressWarnings("unchecked") protected Object doExecute(Object sourceArray) throws Exception { - Class implClass = CollectionConversionUtils.getImpl(getTargetCollectionType()); + Class implClass = ConversionUtils.getCollectionImpl((Class) getTargetCollectionType()); Collection collection = (Collection) implClass.newInstance(); int length = Array.getLength(sourceArray); ConversionExecutor elementConverter = getElementConverter(); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CharacterToNumberFactory.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CharacterToNumberFactory.java index 54d48de9850..840430fedd6 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CharacterToNumberFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CharacterToNumberFactory.java @@ -21,10 +21,11 @@ import org.springframework.util.NumberUtils; /** * Converts from a Character to any JDK-standard Number implementation. - * + *

* 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. - * + * @author Keith Donald + * @since 3.0 * @see java.lang.Byte * @see java.lang.Short * @see java.lang.Integer @@ -33,9 +34,7 @@ import org.springframework.util.NumberUtils; * @see java.lang.Float * @see java.lang.Double * @see java.math.BigDecimal - * @see NumberUtils - * - * @author Keith Donald + * @see NumberUtils */ public class CharacterToNumberFactory implements ConverterFactory { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArray.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArray.java index ae2ef8aa152..4b1e51a856a 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArray.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArray.java @@ -23,14 +23,15 @@ import org.springframework.core.convert.TypeDescriptor; /** * Special converter that converts from target collection to a source array. - * * @author Keith Donald + * @since 3.0 */ +@SuppressWarnings("unchecked") class CollectionToArray extends AbstractCollectionConverter { - public CollectionToArray(TypeDescriptor sourceArrayType, TypeDescriptor targetCollectionType, + public CollectionToArray(TypeDescriptor sourceCollectionType, TypeDescriptor targetArrayType, GenericTypeConverter conversionService) { - super(sourceArrayType, targetCollectionType, conversionService); + super(sourceCollectionType, targetArrayType, conversionService); } @Override diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollection.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollection.java index c70318979c4..04952b0cbfc 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollection.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollection.java @@ -22,9 +22,10 @@ import org.springframework.core.convert.TypeDescriptor; /** * A converter that can convert from one collection type to another. - * * @author Keith Donald + * @since 3.0 */ +@SuppressWarnings("unchecked") class CollectionToCollection extends AbstractCollectionConverter { public CollectionToCollection(TypeDescriptor sourceCollectionType, TypeDescriptor targetCollectionType, @@ -33,10 +34,9 @@ class CollectionToCollection extends AbstractCollectionConverter { } @Override - @SuppressWarnings("unchecked") protected Object doExecute(Object source) throws Exception { Collection sourceCollection = (Collection) source; - Class implClass = CollectionConversionUtils.getImpl(getTargetCollectionType()); + Class implClass = ConversionUtils.getCollectionImpl((Class) getTargetCollectionType()); Collection targetCollection = (Collection) implClass.newInstance(); ConversionExecutor elementConverter = getElementConverter(sourceCollection); Iterator it = sourceCollection.iterator(); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionExecutor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionExecutor.java index 93e89d7c215..9de83747b2f 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionExecutor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionExecutor.java @@ -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 * target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific * converter. - * * @author Keith Donald + * @since 3.0 */ public interface ConversionExecutor { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultTypeConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultTypeConverter.java index 27d1b859702..c5fde2d7c10 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultTypeConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultTypeConverter.java @@ -15,12 +15,11 @@ */ package org.springframework.core.convert.support; - /** * Default implementation of a conversion service. Will automatically register from string converters for * a number of standard Java types like Class, Number, Boolean and so on. - * * @author Keith Donald + * @since 3.0 */ public class DefaultTypeConverter extends GenericTypeConverter { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericTypeConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericTypeConverter.java index a9aa8082d63..adc644a05fa 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericTypeConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericTypeConverter.java @@ -26,9 +26,9 @@ import java.util.List; import java.util.Map; import org.springframework.core.GenericTypeResolver; -import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.ConverterNotFoundException; 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.ConverterFactory; import org.springframework.core.convert.converter.ConverterInfo; @@ -36,9 +36,12 @@ import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.util.Assert; /** - * Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default. - * TODO - object to collection/map converters + * Base implementation of a conversion service. + * Initially empty, e.g. no converters are registered by default. * @author Keith Donald + * @see #add(Converter) + * @see #add(ConverterFactory) + * @since 3.0 */ @SuppressWarnings("unchecked") public class GenericTypeConverter implements TypeConverter, ConverterRegistry { @@ -69,6 +72,9 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { public void add(Converter converter) { List typeInfo = getRequiredTypeInfo(converter); + if (typeInfo == null) { + throw new IllegalArgumentException("Unable to the determine sourceType and targetType your Converter converts between"); + } Class sourceType = (Class) typeInfo.get(0); Class targetType = (Class) typeInfo.get(1); Map sourceMap = getSourceMap(sourceType); @@ -77,6 +83,9 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { public void add(ConverterFactory converterFactory) { List typeInfo = getRequiredTypeInfo(converterFactory); + if (typeInfo == null) { + throw new IllegalArgumentException("Unable to the determine sourceType and targetType your ConverterFactory creates Converters to convert between"); + } Class sourceType = (Class) typeInfo.get(0); Class targetType = (Class) typeInfo.get(1); 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(targetType, "The targetType to convert to is required"); if (targetType.getType() == null) { - // TODO for Andy - is this correct way to handle the Null TypedValue? return NoOpConversionExecutor.INSTANCE; } + // TODO clean this if/else code up TypeDescriptor sourceType = TypeDescriptor.valueOf(sourceClass); if (sourceType.isArray()) { if (targetType.isArray()) { @@ -161,14 +170,19 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { return new ArrayToCollection(sourceType, targetType, this); } else if (targetType.isMap()) { if (sourceType.getElementType().equals(String.class)) { - // string array to map; with string element values in format foo=bar return new StringArrayToMap(sourceType, targetType, this); } else { + // array to map return null; } } else { - // array to object - return null; + if (targetType.equals(String.class)) { + // array to string; + return null; + } else { + // array to object + return null; + } } } if (sourceType.isCollection()) { @@ -178,14 +192,19 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { return new CollectionToArray(sourceType, targetType, this); } else if (targetType.isMap()) { if (sourceType.getElementType().equals(String.class)) { - // string collection to map; with string element values in format foo=bar - return null; + return new StringCollectionToMap(sourceType, targetType, this); } else { + // object collection to map return null; } } else { - // collection to object - return null; + if (targetType.equals(String.class)) { + // collection to string; + return null; + } else { + // collection to object + return null; + } } } if (sourceType.isMap()) { @@ -193,16 +212,16 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { return new MapToMap(sourceType, targetType, this); } else if (targetType.isArray()) { if (targetType.getElementType().equals(String.class)) { - // map to string array; with string element values in format foo=bar - return null; + return new MapToStringArray(sourceType, targetType, this); } else { + // map to object array return null; } } else if (targetType.isCollection()) { if (targetType.getElementType().equals(String.class)) { - // map to string collection; with string element values in format foo=bar - return null; + return new MapToStringCollection(sourceType, targetType, this); } else { + // map to object collection return null; } } else { @@ -211,18 +230,24 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { } } if (targetType.isArray()) { - // object to array - return null; + if (sourceType.getType().equals(String.class)) { + return new StringToArray(sourceType, targetType, this); + } else { + return new ObjectToArray(sourceType, targetType, this); + } } if (targetType.isCollection()) { - // object to collection - return null; + if (sourceType.getType().equals(String.class)) { + return new StringToCollection(sourceType, targetType, this); + } else { + return new ObjectToCollection(sourceType, targetType, this); + } } if (targetType.isMap()) { - // object to map if (sourceType.getType().equals(String.class)) { return new StringToMap(sourceType, targetType, this); } else { + // object to map return null; } } @@ -246,43 +271,52 @@ public class GenericTypeConverter implements TypeConverter, ConverterRegistry { typeInfo.add(info.getSourceType()); typeInfo.add(info.getTargetType()); return typeInfo; + } else { + return getConverterTypeInfo(converter.getClass()); } - Class classToIntrospect = converter.getClass(); + } + + private List getConverterTypeInfo(Class converterClass) { + Class classToIntrospect = converterClass; while (classToIntrospect != null) { - Type[] genericInterfaces = classToIntrospect.getGenericInterfaces(); - for (Type genericInterface : genericInterfaces) { - if (genericInterface instanceof ParameterizedType) { - ParameterizedType pInterface = (ParameterizedType) genericInterface; - if (Converter.class.isAssignableFrom((Class) pInterface.getRawType()) - || ConverterFactory.class.isAssignableFrom((Class) pInterface.getRawType())) { - Class s = getParameterClass(pInterface.getActualTypeArguments()[0], converter.getClass()); - Class t = getParameterClass(pInterface.getActualTypeArguments()[1], converter.getClass()); - typeInfo.add(getParameterClass(s, converter.getClass())); - typeInfo.add(getParameterClass(t, converter.getClass())); - break; + Type[] ifcs = classToIntrospect.getGenericInterfaces(); + for (Type ifc : ifcs) { + if (ifc instanceof ParameterizedType) { + ParameterizedType paramIfc = (ParameterizedType) ifc; + Type rawType = paramIfc.getRawType(); + if (Converter.class.equals(rawType) || ConverterFactory.class.equals(rawType)) { + List typeInfo = new ArrayList(2); + Type arg1 = paramIfc.getActualTypeArguments()[0]; + if (arg1 instanceof TypeVariable) { + arg1 = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg1, converterClass); + } + 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(); } - if (typeInfo.size() != 2) { - throw new IllegalArgumentException("Unable to extract source and target class arguments from Converter [" - + converter.getClass().getName() + "]; does the Converter specify the generic types?"); - } - return typeInfo; + return null; } - - 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) { Map sourceMap = (Map) sourceTypeConverters.get(sourceType); if (sourceMap == null) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMap.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMap.java index bf59ebc34fd..4cf352ef97b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMap.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMap.java @@ -15,11 +15,8 @@ */ package org.springframework.core.convert.support; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; import org.springframework.core.convert.ConversionFailedException; 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. * @author Keith Donald + * @since 3.0 */ @SuppressWarnings("unchecked") class MapToMap implements ConversionExecutor { @@ -37,7 +35,7 @@ class MapToMap implements ConversionExecutor { private GenericTypeConverter conversionService; - private EntryConverter entryConverter; + private MapEntryConverter entryConverter; /** * Creates a new map-to-map converter @@ -52,23 +50,23 @@ class MapToMap implements ConversionExecutor { this.entryConverter = createEntryConverter(); } - private EntryConverter createEntryConverter() { + private MapEntryConverter createEntryConverter() { if (sourceType.isMapEntryTypeKnown() && targetType.isMapEntryTypeKnown()) { ConversionExecutor keyConverter = conversionService.getConversionExecutor(sourceType.getMapKeyType(), TypeDescriptor.valueOf(targetType.getMapKeyType())); ConversionExecutor valueConverter = conversionService.getConversionExecutor(sourceType.getMapValueType(), TypeDescriptor.valueOf(targetType.getMapValueType())); - return new EntryConverter(keyConverter, valueConverter); + return new MapEntryConverter(keyConverter, valueConverter); } else { - return EntryConverter.NO_OP_INSTANCE; + return MapEntryConverter.NO_OP_INSTANCE; } } public Object execute(Object source) throws ConversionFailedException { try { Map map = (Map) source; - Map targetMap = (Map) getImpl(targetType.getType()).newInstance(); - EntryConverter converter = getEntryConverter(map); + Map targetMap = (Map) ConversionUtils.getMapImpl(targetType.getType()).newInstance(); + MapEntryConverter converter = getEntryConverter(map); Iterator> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); @@ -80,9 +78,9 @@ class MapToMap implements ConversionExecutor { } } - private EntryConverter getEntryConverter(Map map) { - EntryConverter entryConverter = this.entryConverter; - if (entryConverter == EntryConverter.NO_OP_INSTANCE) { + private MapEntryConverter getEntryConverter(Map map) { + MapEntryConverter entryConverter = this.entryConverter; + if (entryConverter == MapEntryConverter.NO_OP_INSTANCE) { Class targetKeyType = targetType.getMapKeyType(); Class targetValueType = targetType.getMapValueType(); if (targetKeyType != null && targetValueType != null) { @@ -105,59 +103,10 @@ class MapToMap implements ConversionExecutor { break; } } - entryConverter = new EntryConverter(keyConverter, valueConverter); + entryConverter = new MapEntryConverter(keyConverter, valueConverter); } } 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; - } - } - - } - + } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NoOpConversionExecutor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NoOpConversionExecutor.java index 12e533480d3..c1a62f9535b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NoOpConversionExecutor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NoOpConversionExecutor.java @@ -18,18 +18,20 @@ package org.springframework.core.convert.support; 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 { public static final ConversionExecutor INSTANCE = new NoOpConversionExecutor(); - private NoOpConversionExecutor() { - - } - public Object execute(Object source) throws ConversionFailedException { + // does nothing return source; } + private NoOpConversionExecutor() { + } + } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToCharacter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToCharacter.java index 8759e5142fc..db6657c11bb 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToCharacter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToCharacter.java @@ -20,7 +20,7 @@ import org.springframework.util.NumberUtils; /** * Converts from any JDK-standard Number implementation to a Character. - * + * @author Keith Donald * @see java.lang.Character * @see java.lang.Short * @see java.lang.Integer @@ -30,8 +30,7 @@ import org.springframework.util.NumberUtils; * @see java.lang.Double * @see java.math.BigDecimal * @see NumberUtils - * - * @author Keith Donald + * @since 3.0 */ public class NumberToCharacter implements Converter { public Character convert(Number source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToNumberFactory.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToNumberFactory.java index 52cebbe0c0a..979edde49f0 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToNumberFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/NumberToNumberFactory.java @@ -21,10 +21,10 @@ import org.springframework.util.NumberUtils; /** * Converts from any JDK-standard Number implementation to any other JDK-standard Number implementation. - * + *

* 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. - * + * @author Keith Donald * @see java.lang.Byte * @see java.lang.Short * @see java.lang.Integer @@ -34,8 +34,7 @@ import org.springframework.util.NumberUtils; * @see java.lang.Double * @see java.math.BigDecimal * @see NumberUtils - * - * @author Keith Donald + * @since 3.0 */ public class NumberToNumberFactory implements ConverterFactory { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToString.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToString.java index b2dd3461568..e6c7074d830 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToString.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToString.java @@ -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; 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. * Used by the {@link DefaultTypeConverter} as a fallback if there are no other explicit to string converters registered. * @author Keith Donald + * @since 3.0 */ public class ObjectToString implements Converter { public String convert(Object source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StaticConversionExecutor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StaticConversionExecutor.java index fa3cd6c7b62..2622043d2aa 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StaticConversionExecutor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StaticConversionExecutor.java @@ -23,6 +23,7 @@ import org.springframework.core.style.ToStringCreator; /** * Default conversion executor implementation for converters. * @author Keith Donald + * @since 3.0 */ @SuppressWarnings("unchecked") class StaticConversionExecutor implements ConversionExecutor { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMap.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMap.java index d1fada0931d..49762688560 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMap.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMap.java @@ -15,14 +15,18 @@ */ package org.springframework.core.convert.support; -import java.util.HashMap; +import java.lang.reflect.Array; import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; import org.springframework.core.convert.ConversionFailedException; 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") class StringArrayToMap implements ConversionExecutor { @@ -32,7 +36,7 @@ class StringArrayToMap implements ConversionExecutor { private GenericTypeConverter conversionService; - private EntryConverter entryConverter; + private MapEntryConverter entryConverter; public StringArrayToMap(TypeDescriptor sourceType, TypeDescriptor targetType, GenericTypeConverter conversionService) { this.sourceType = sourceType; @@ -41,24 +45,25 @@ class StringArrayToMap implements ConversionExecutor { this.entryConverter = createEntryConverter(); } - private EntryConverter createEntryConverter() { + private MapEntryConverter createEntryConverter() { if (targetType.isMapEntryTypeKnown()) { ConversionExecutor keyConverter = conversionService.getConversionExecutor(String.class, TypeDescriptor.valueOf(targetType.getMapKeyType())); ConversionExecutor valueConverter = conversionService.getConversionExecutor(String.class, TypeDescriptor.valueOf(targetType.getMapValueType())); - return new EntryConverter(keyConverter, valueConverter); + return new MapEntryConverter(keyConverter, valueConverter); } else { - return EntryConverter.NO_OP_INSTANCE; + return MapEntryConverter.NO_OP_INSTANCE; } } public Object execute(Object source) throws ConversionFailedException { try { - Map targetMap = (Map) getImpl(targetType.getType()).newInstance(); - String[] array = (String[]) source; - for (String string : array) { - String[] fields = string.split("="); + Map targetMap = (Map) ConversionUtils.getMapImpl(targetType.getType()).newInstance(); + int length = Array.getLength(source); + for (int i = 0; i < length; i++) { + String property = (String) Array.get(source, i); + String[] fields = property.split("="); String key = fields[0]; String value = fields[1]; 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; - } - } - - } - } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigDecimal.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigDecimal.java index a7e7c6689bc..27eda24d062 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigDecimal.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigDecimal.java @@ -21,8 +21,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a BigDecimal using {@link BigDecimal#BigDecimal(String). - * * @author Keith Donald + * @since 3.0 */ public class StringToBigDecimal implements Converter { public BigDecimal convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigInteger.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigInteger.java index b2757712b9b..d3cae701897 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigInteger.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBigInteger.java @@ -21,8 +21,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a BigInteger using {@link BigInteger#BigInteger(String)}. - * * @author Keith Donald + * @since 3.0 */ public class StringToBigInteger implements Converter { public BigInteger convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBoolean.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBoolean.java index 21337b42346..dd481edb645 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBoolean.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToBoolean.java @@ -20,9 +20,9 @@ import org.springframework.core.convert.converter.Converter; /** * Converts String to a Boolean. The trueString and falseStrings are configurable. - * - * @see #StringToBoolean(String, String) * @author Keith Donald + * @see #StringToBoolean(String, String) + * @since 3.0 */ public class StringToBoolean implements Converter { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToByte.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToByte.java index a6dcaaccbe0..4eeceffaa26 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToByte.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToByte.java @@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a Byte and back. - * * @author Keith Donald + * @since 3.0 */ public class StringToByte implements Converter { public Byte convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCharacter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCharacter.java index f1f67453132..03b726e24a9 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCharacter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCharacter.java @@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a Character and back. - * * @author Keith Donald + * @since 3.0 */ public class StringToCharacter implements Converter { public Character convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToDouble.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToDouble.java index f67ec9bb781..68e996d84e9 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToDouble.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToDouble.java @@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a Double using {@link Double#valueOf(String)}. - * * @author Keith Donald + * @since 3.0 */ public class StringToDouble implements Converter { public Double convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumFactory.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumFactory.java index 7cf8993bbdd..68b9e7082a8 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToEnumFactory.java @@ -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; import org.springframework.core.convert.converter.Converter; 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") public class StringToEnumFactory implements ConverterFactory { @@ -10,14 +31,22 @@ public class StringToEnumFactory implements ConverterFactory { return new StringToEnum(targetType); } - class StringToEnum implements Converter { + class StringToEnum implements Converter, ConverterInfo { private Class enumType; public StringToEnum(Class enumType) { this.enumType = enumType; } - + + public Class getSourceType() { + return String.class; + } + + public Class getTargetType() { + return enumType; + } + public T convert(String source) throws Exception { return (T) Enum.valueOf(enumType, source); } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToFloat.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToFloat.java index b734722439c..e2b3a101abe 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToFloat.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToFloat.java @@ -19,8 +19,8 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to Float using {@link Float#valueOf(String)}. - * * @author Keith Donald + * @since 3.0 */ public class StringToFloat implements Converter { public Float convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToInteger.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToInteger.java index b214b6eea16..0d0ae2164ac 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToInteger.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToInteger.java @@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to an Integer using {@link Integer#valueOf(String)}. * @author Keith Donald + * @since 3.0 */ public class StringToInteger implements Converter { public Integer convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLocale.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLocale.java index ab291b6c4c8..072e0d1a820 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLocale.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLocale.java @@ -23,6 +23,7 @@ import org.springframework.util.StringUtils; /** * Converts a String to a Locale using {@link StringUtils#parseLocaleString(String)}. * @author Keith Donald + * @since 3.0 */ public class StringToLocale implements Converter { public Locale convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLong.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLong.java index 218ac542326..f69d9b82395 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLong.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToLong.java @@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a Long using {@link Long#valueOf(String)}. * @author Keith Donald + * @since 3.0 */ public class StringToLong implements Converter { public Long convert(String source) { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMap.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMap.java index e07eadf2b7f..feb8da7f27f 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMap.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMap.java @@ -18,6 +18,18 @@ package org.springframework.core.convert.support; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.TypeDescriptor; +/** + * Converts a String to a map. + * The String should be in the format: + *

+ * key=value
+ * key=value
+ * key=value
+ * key=value
+ * 
+ * @author Keith Donald + * @since 3.0 + */ @SuppressWarnings("unchecked") class StringToMap implements ConversionExecutor { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToShort.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToShort.java index 0262fb11993..a4d16f87e16 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToShort.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToShort.java @@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter; /** * Converts a String to a Short using {@link Short#valueOf(String)}. * @author Keith Donald + * @since 3.0 */ public class StringToShort implements Converter { public Short convert(String source) { diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericTypeConverterTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericTypeConverterTests.java index 3876b68c18d..bfd8796f792 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericTypeConverterTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericTypeConverterTests.java @@ -219,7 +219,6 @@ public class GenericTypeConverterTests { public Map genericMap = new HashMap(); @Test - @Ignore public void convertMapToMap() throws Exception { Map foo = new HashMap(); foo.put("1", "BAR"); @@ -231,15 +230,15 @@ public class GenericTypeConverterTests { assertEquals(map.get(2), FooEnum.BAZ); } - @Ignore @Test public void convertObjectToArray() { String[] result = (String[]) converter.convert("1,2,3", String[].class); - assertEquals(1, result.length); - assertEquals("1,2,3", result[0]); + assertEquals(3, result.length); + assertEquals("1", result[0]); + assertEquals("2", result[1]); + assertEquals("3", result[2]); } - @Ignore @Test public void convertObjectToArrayWithElementConversion() { converter.add(new StringToInteger());