From ffbfa2992ce809cd3273c90334340741a006b4a5 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Wed, 4 Nov 2009 17:07:25 +0000 Subject: [PATCH] polish --- .../support/FormattingConversionService.java | 14 +- ... => FormattingConversionServiceTests.java} | 3 +- .../support/ConditionalGenericConverter.java | 14 +- .../convert/support/ConverterMatcher.java | 36 +++ .../support/DefaultConversionService.java | 17 ++ .../support/GenericConversionService.java | 144 +++++++-- .../GenericConversionServiceTests.java | 285 ++++++++++++------ 7 files changed, 372 insertions(+), 141 deletions(-) rename org.springframework.context/src/test/java/org/springframework/ui/format/support/{GenericFormattingServiceTests.java => FormattingConversionServiceTests.java} (97%) create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/ConverterMatcher.java diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/support/FormattingConversionService.java b/org.springframework.context/src/main/java/org/springframework/ui/format/support/FormattingConversionService.java index b2dd8c8b7c..5be556492f 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/format/support/FormattingConversionService.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/support/FormattingConversionService.java @@ -82,7 +82,7 @@ public class FormattingConversionService implements FormatterRegistry, Conversio + "]; does the factory parameterize the generic type?"); } Set> fieldTypes = annotationFormatterFactory.getFieldTypes(); - for (Class fieldType : fieldTypes) { + for (final Class fieldType : fieldTypes) { this.conversionService.addGenericConverter(fieldType, String.class, new ConditionalGenericConverter() { public boolean matches(TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) { return sourceFieldType.getAnnotation(annotationType) != null; @@ -90,7 +90,10 @@ public class FormattingConversionService implements FormatterRegistry, Conversio public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Printer printer = annotationFormatterFactory.getPrinter(sourceType.getAnnotation(annotationType), targetType.getType()); return new PrinterConverter(printer, conversionService).convert(source, sourceType, targetType); - } + } + public String toString() { + return "@" + annotationType.getName() + " " + fieldType.getName() + " -> " + String.class.getName(); + } }); this.conversionService.addGenericConverter(String.class, fieldType, new ConditionalGenericConverter() { public boolean matches(TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) { @@ -99,6 +102,9 @@ public class FormattingConversionService implements FormatterRegistry, Conversio public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Parser parser = annotationFormatterFactory.getParser(targetType.getAnnotation(annotationType), targetType.getType()); return new ParserConverter(parser, conversionService).convert(source, sourceType, targetType); + } + public String toString() { + return String.class.getName() + " -> @" + annotationType.getName() + " " + fieldType.getName(); } }); } @@ -127,6 +133,10 @@ public class FormattingConversionService implements FormatterRegistry, Conversio return this.conversionService.convert(source, sourceType, targetType); } + public String toString() { + return this.conversionService.toString(); + } + // internal helpers @SuppressWarnings("unchecked") diff --git a/org.springframework.context/src/test/java/org/springframework/ui/format/support/GenericFormattingServiceTests.java b/org.springframework.context/src/test/java/org/springframework/ui/format/support/FormattingConversionServiceTests.java similarity index 97% rename from org.springframework.context/src/test/java/org/springframework/ui/format/support/GenericFormattingServiceTests.java rename to org.springframework.context/src/test/java/org/springframework/ui/format/support/FormattingConversionServiceTests.java index a3e65c93c6..dec00f0a46 100644 --- a/org.springframework.context/src/test/java/org/springframework/ui/format/support/GenericFormattingServiceTests.java +++ b/org.springframework.context/src/test/java/org/springframework/ui/format/support/FormattingConversionServiceTests.java @@ -41,7 +41,7 @@ import org.springframework.ui.format.number.IntegerFormatter; * @author Keith Donald * @author Juergen Hoeller */ -public class GenericFormattingServiceTests { +public class FormattingConversionServiceTests { private FormattingConversionService formattingService; @@ -93,6 +93,7 @@ public class GenericFormattingServiceTests { } }); formattingService.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory()); + System.out.println(this.formattingService); String formatted = (String) formattingService.convert(new LocalDate(2009, 10, 31).toDateTimeAtCurrentTime() .toDate(), new TypeDescriptor(Model.class.getField("date")), TypeDescriptor.valueOf(String.class)); assertEquals("10/31/09", formatted); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConditionalGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConditionalGenericConverter.java index 717a9f26e1..6888fad6f7 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConditionalGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConditionalGenericConverter.java @@ -15,23 +15,13 @@ */ package org.springframework.core.convert.support; -import org.springframework.core.convert.TypeDescriptor; - /** - * A generic converter that conditionally executes. + * A generic converter that, as a ConverterMatcher, conditionally executes. * Often used when selectively matching custom conversion logic based on the presence of a field or class-level annotation. * For example, when converting from a String to a Date field, an implementation might return true if the target field has also been annotated with @DateTimeFormat. * @author Keith Donald * @since 3.0 */ -public interface ConditionalGenericConverter extends GenericConverter { - - /** - * Should the conversion between sourceFieldType and targetFieldType be performed? - * @param sourceFieldType the type descriptor of the field we are converting from - * @param targetFieldType the type descriptor of the field we are converting to - * @return true if conversion should be performed, false otherwise - */ - boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); +public interface ConditionalGenericConverter extends GenericConverter, ConverterMatcher { } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConverterMatcher.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConverterMatcher.java new file mode 100644 index 0000000000..fe36c9d385 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConverterMatcher.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-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.TypeDescriptor; + +/** + * A rule that determines if a particular Converter of S to T matches given a request to convert between a field of type S and a field of type T. + * Often used to selectively apply custom type conversion logic based on the presence of a field annotation. + * For example, when converting from a String to a Date field, an implementation might return true only if the target Date field has also been annotated with @DateTimeFormat. + * @author Keith Donald + * @since 3.0 + */ +public interface ConverterMatcher { + + /** + * Should the Converter from sourceType to targetType currently under consideration be selected? + * @param sourceType the type descriptor of the field we are converting from + * @param targetType the type descriptor of the field we are converting to + * @return true if conversion should be performed, false otherwise + */ + boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java index dba0a1300a..5c0f8fe330 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java @@ -16,7 +16,9 @@ package org.springframework.core.convert.support; +import java.util.Collection; import java.util.Locale; +import java.util.Map; /** * Default implementation of a conversion service. Will automatically register from string @@ -32,6 +34,21 @@ public class DefaultConversionService extends GenericConversionService { * Create a new default conversion service, installing the default converters. */ public DefaultConversionService() { + addGenericConverter(Object[].class, Object[].class, new ArrayToArrayConverter(this)); + addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter(this)); + addGenericConverter(Object[].class, Map.class, new ArrayToMapConverter(this)); + addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter(this)); + addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter(this)); + addGenericConverter(Collection.class, Object[].class, new CollectionToArrayConverter(this)); + addGenericConverter(Collection.class, Map.class, new CollectionToMapConverter(this)); + addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter(this)); + addGenericConverter(Map.class, Map.class, new MapToMapConverter(this)); + addGenericConverter(Map.class, Object[].class, new MapToArrayConverter(this)); + addGenericConverter(Map.class, Collection.class, new MapToCollectionConverter(this)); + addGenericConverter(Map.class, Object.class, new MapToObjectConverter(this)); + addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter(this)); + addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter(this)); + addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(this)); addConverter(String.class, Boolean.class, new StringToBooleanConverter()); addConverter(String.class, Character.class, new StringToCharacterConverter()); addConverter(String.class, Locale.class, new StringToLocaleConverter()); diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index 2b6e1fefcd..21dc791411 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -61,28 +61,6 @@ public class GenericConversionService implements ConversionService, ConverterReg } }; - /** - * Create a new GenericConversionService. - * Generic converters for Collection types are registered. - */ - public GenericConversionService() { - addGenericConverter(Object[].class, Object[].class, new ArrayToArrayConverter(this)); - addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter(this)); - addGenericConverter(Object[].class, Map.class, new ArrayToMapConverter(this)); - addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter(this)); - addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter(this)); - addGenericConverter(Collection.class, Object[].class, new CollectionToArrayConverter(this)); - addGenericConverter(Collection.class, Map.class, new CollectionToMapConverter(this)); - addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter(this)); - addGenericConverter(Map.class, Map.class, new MapToMapConverter(this)); - addGenericConverter(Map.class, Object[].class, new MapToArrayConverter(this)); - addGenericConverter(Map.class, Collection.class, new MapToCollectionConverter(this)); - addGenericConverter(Map.class, Object.class, new MapToObjectConverter(this)); - addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter(this)); - addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter(this)); - addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(this)); - } - /** * Registers the converters in the set provided. * JavaBean-friendly alternative to calling {@link #addConverter(Converter)}. @@ -191,7 +169,18 @@ public class GenericConversionService implements ConversionService, ConverterReg public void addGenericConverter(Class sourceType, Class targetType, GenericConverter converter) { getMatchableConvertersList(sourceType, targetType).add(converter); } - + + /** + * Registers a GenericConverter for the source/target type pair that will only be matched if the provided matcher returns true. + * @param sourceType the source type to convert from + * @param targetType the target type to convert to + * @param matcher a matcher can restrict a match of the converter based on source and target runtime field types + * @param converter the generic converter. + */ + public void addGenericConverter(Class sourceType, Class targetType, GenericConverter converter, ConverterMatcher matcher) { + getMatchableConvertersList(sourceType, targetType).add(matcher, converter); + } + /** * Registers a Converter with the sourceType and targetType to index on specified explicitly. * This method performs better than {@link #addConverter(Converter)} because there parameterized types S and T don't have to be discovered. @@ -214,6 +203,22 @@ public class GenericConversionService implements ConversionService, ConverterReg addGenericConverter(sourceType, targetType, new ConverterFactoryAdapter(converterFactory)); } + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ConversionService converters = ").append("\n"); + for (Map, MatchableConverters> targetConverters : this.converters.values()) { + for (MatchableConverters matchable : targetConverters.values()) { + builder.append("\t"); + builder.append(matchable); + builder.append("\n"); + } + } + if (this.parent != null) { + builder.append("parent = ").append(this.parent); + } + return builder.toString(); + } + // subclassing hooks /** @@ -402,7 +407,8 @@ public class GenericConversionService implements ConversionService, ConverterReg } } - private GenericConverter matchConverter(MatchableConverters matchable, TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) { + private GenericConverter matchConverter(MatchableConverters matchable, TypeDescriptor sourceFieldType, + TypeDescriptor targetFieldType) { return matchable != null ? matchable.matchConverter(sourceFieldType, targetFieldType) : null; } @@ -421,6 +427,10 @@ public class GenericConversionService implements ConversionService, ConverterReg } return this.converter.convert(source); } + + public String toString() { + return this.converter.toString(); + } } @SuppressWarnings("unchecked") @@ -438,29 +448,97 @@ public class GenericConversionService implements ConversionService, ConverterReg } return this.converterFactory.getConverter(targetType.getObjectType()).convert(source); } + + public String toString() { + return this.converterFactory.toString(); + } + } private static class MatchableConverters { - private LinkedList matchableConverters = new LinkedList(); + private static final ConverterMatcher ALWAYS_MATCHES = new ConverterMatcher() { + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + return true; + } + }; + + private LinkedList matchableConverters = new LinkedList(); public void add(GenericConverter converter) { - this.matchableConverters.addFirst(converter); + if (converter instanceof ConverterMatcher) { + add((ConverterMatcher) converter, converter); + } else { + add(ALWAYS_MATCHES, converter); + } + } + + public void add(ConverterMatcher matcher, GenericConverter converter) { + MatchableConverter matchable = new MatchableConverter(matcher, converter); + int index = this.matchableConverters.indexOf(matchable); + if (index == -1) { + this.matchableConverters.addFirst(new MatchableConverter(matcher, converter)); + } else { + this.matchableConverters.set(index, matchable); + } } public GenericConverter matchConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { - for (GenericConverter matchable : this.matchableConverters) { - if (!(matchable instanceof ConditionalGenericConverter)) { - return matchable; - } - ConditionalGenericConverter conditional = (ConditionalGenericConverter) matchable; - if (conditional.matches(sourceType, targetType)) { - return matchable; + for (MatchableConverter matchable : this.matchableConverters) { + if (matchable.matches(sourceType, targetType)) { + return matchable.getConverter(); } } return null; } + + public String toString() { + if (this.matchableConverters.size() == 1) { + return this.matchableConverters.get(0).toString(); + } else { + return "[MatchableConverters = " + this.matchableConverters + "]"; + } + } + + private static class MatchableConverter { + + private ConverterMatcher matcher; + + private GenericConverter converter; + + public MatchableConverter(ConverterMatcher matcher, GenericConverter converter) { + this.matcher = matcher; + this.converter = converter; + } + + public GenericConverter getConverter() { + return this.converter; + } + + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + return this.matcher.matches(sourceType, targetType); + } + + public int hashCode() { + return this.matcher.hashCode(); + } + public boolean equals(Object o) { + if (!(o instanceof MatchableConverter)) { + return false; + } + MatchableConverter matchable = (MatchableConverter) o; + return this.matcher.equals(matchable.matcher); + } + + public String toString() { + if (matcher == ALWAYS_MATCHES || matcher == converter) { + return this.converter.toString(); + } else { + return "if (" + this.matcher + ") " + this.converter; + } + } + } } } \ No newline at end of file diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java index 7a9b42a6e2..6089147cbf 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java @@ -157,6 +157,8 @@ public class GenericConversionServiceTests { @Test public void convertArrayToPrimitiveArray() { + conversionService.addGenericConverter(Object[].class, Object[].class, new ArrayToArrayConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); int[] result = conversionService.convert(new String[] { "1", "2", "3" }, int[].class); assertEquals(1, result[0]); @@ -174,6 +176,8 @@ public class GenericConversionServiceTests { @Test public void convertArrayToListInterface() { + conversionService.addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter( + conversionService)); List result = conversionService.convert(new String[] { "1", "2", "3" }, List.class); assertEquals("1", result.get(0)); assertEquals("2", result.get(1)); @@ -184,6 +188,8 @@ public class GenericConversionServiceTests { @Test public void convertArrayToListGenericTypeConversion() throws Exception { + conversionService.addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); List result = (List) conversionService.convert(new String[] { "1", "2", "3" }, TypeDescriptor .valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList"))); @@ -194,6 +200,8 @@ public class GenericConversionServiceTests { @Test public void convertArrayToListImpl() { + conversionService.addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter( + conversionService)); LinkedList result = conversionService.convert(new String[] { "1", "2", "3" }, LinkedList.class); assertEquals("1", result.get(0)); assertEquals("2", result.get(1)); @@ -202,17 +210,43 @@ public class GenericConversionServiceTests { @Test(expected = ConversionFailedException.class) public void convertArrayToAbstractList() { + conversionService.addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionConverter( + conversionService)); conversionService.convert(new String[] { "1", "2", "3" }, AbstractList.class); } + @Test + public void convertArrayToMap() { + conversionService.addGenericConverter(Object[].class, Map.class, new ArrayToMapConverter(conversionService)); + Map result = conversionService.convert(new String[] { "foo=bar", "bar=baz", "baz=boop" }, Map.class); + assertEquals("bar", result.get("foo")); + assertEquals("baz", result.get("bar")); + assertEquals("boop", result.get("baz")); + } + + @Test + public void convertArrayToMapWithElementConversion() throws Exception { + conversionService.addGenericConverter(Object[].class, Map.class, new ArrayToMapConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverterFactory(new StringToEnumConverterFactory()); + Map result = (Map) conversionService.convert(new String[] { "1=BAR", "2=BAZ" }, TypeDescriptor + .valueOf(String[].class), new TypeDescriptor(getClass().getField("genericMap"))); + assertEquals(FooEnum.BAR, result.get(1)); + assertEquals(FooEnum.BAZ, result.get(2)); + } + @Test public void convertArrayToString() { + conversionService.addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter( + conversionService)); String result = conversionService.convert(new String[] { "1", "2", "3" }, String.class); assertEquals("1,2,3", result); } @Test public void convertArrayToStringWithElementConversion() { + conversionService.addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter( + conversionService)); conversionService.addConverter(new ObjectToStringConverter()); String result = conversionService.convert(new Integer[] { 1, 2, 3 }, String.class); assertEquals("1,2,3", result); @@ -220,12 +254,16 @@ public class GenericConversionServiceTests { @Test public void convertEmptyArrayToString() { + conversionService.addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter( + conversionService)); String result = conversionService.convert(new String[0], String.class); assertEquals("", result); } @Test public void convertArrayToObject() { + conversionService.addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter( + conversionService)); Object[] array = new Object[] { 3L }; Object result = conversionService.convert(array, Object.class); assertEquals(3L, result); @@ -233,6 +271,8 @@ public class GenericConversionServiceTests { @Test public void convertArrayToObjectWithElementConversion() { + conversionService.addGenericConverter(Object[].class, Object.class, new ArrayToObjectConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); String[] array = new String[] { "3" }; Integer result = conversionService.convert(array, Integer.class); @@ -241,6 +281,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToArray() { + conversionService.addGenericConverter(Collection.class, Object[].class, new CollectionToArrayConverter( + conversionService)); List list = new ArrayList(); list.add("1"); list.add("2"); @@ -253,6 +295,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToArrayWithElementConversion() { + conversionService.addGenericConverter(Collection.class, Object[].class, new CollectionToArrayConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); List list = new ArrayList(); list.add("1"); @@ -266,6 +310,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToCollection() throws Exception { + conversionService.addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); Set foo = new LinkedHashSet(); foo.add("1"); @@ -280,6 +326,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToCollectionNull() throws Exception { + conversionService.addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter( + conversionService)); List bar = (List) conversionService.convert(null, TypeDescriptor.valueOf(LinkedHashSet.class), new TypeDescriptor(getClass().getField("genericList"))); assertNull(bar); @@ -287,6 +335,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToCollectionNotGeneric() throws Exception { + conversionService.addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); Set foo = new LinkedHashSet(); foo.add("1"); @@ -301,6 +351,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToCollectionSpecialCaseSourceImpl() throws Exception { + conversionService.addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); Map map = new LinkedHashMap(); map.put("1", "1"); @@ -315,8 +367,39 @@ public class GenericConversionServiceTests { assertEquals(new Integer(3), bar.get(2)); } + @Test + public void convertCollectionToMap() { + conversionService.addGenericConverter(Collection.class, Map.class, new CollectionToMapConverter( + conversionService)); + List list = new ArrayList(); + list.add("foo=bar"); + list.add("bar=baz"); + list.add("baz=boop"); + Map result = conversionService.convert(list, Map.class); + assertEquals("bar", result.get("foo")); + assertEquals("baz", result.get("bar")); + assertEquals("boop", result.get("baz")); + } + + @Test + public void convertCollectionToMapWithElementConversion() throws Exception { + conversionService.addGenericConverter(Collection.class, Map.class, new CollectionToMapConverter( + conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverterFactory(new StringToEnumConverterFactory()); + List list = new ArrayList(); + list.add("1=BAR"); + list.add("2=BAZ"); + Map result = (Map) conversionService.convert(list, TypeDescriptor.valueOf(List.class), new TypeDescriptor( + getClass().getField("genericMap"))); + assertEquals(FooEnum.BAR, result.get(1)); + assertEquals(FooEnum.BAZ, result.get(2)); + } + @Test public void convertCollectionToString() { + conversionService.addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter( + conversionService)); List list = Arrays.asList(new String[] { "foo", "bar" }); String result = conversionService.convert(list, String.class); assertEquals("foo,bar", result); @@ -324,6 +407,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToStringWithElementConversion() throws Exception { + conversionService.addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter( + conversionService)); conversionService.addConverter(new ObjectToStringConverter()); List list = Arrays.asList(new Integer[] { 3, 5 }); String result = (String) conversionService.convert(list, @@ -333,6 +418,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToObject() { + conversionService.addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter( + conversionService)); List list = Collections.singletonList(3L); Long result = conversionService.convert(list, Long.class); assertEquals(new Long(3), result); @@ -340,6 +427,8 @@ public class GenericConversionServiceTests { @Test public void convertCollectionToObjectWithElementConversion() { + conversionService.addGenericConverter(Collection.class, Object.class, new CollectionToObjectConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); List list = Collections.singletonList("3"); Integer result = conversionService.convert(list, Integer.class); @@ -350,11 +439,12 @@ public class GenericConversionServiceTests { @Test public void convertMapToMap() throws Exception { + conversionService.addGenericConverter(Map.class, Map.class, new MapToMapConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverterFactory(new StringToEnumConverterFactory()); Map foo = new HashMap(); foo.put("1", "BAR"); foo.put("2", "BAZ"); - conversionService.addConverterFactory(new StringToNumberConverterFactory()); - conversionService.addConverterFactory(new StringToEnumConverterFactory()); Map map = (Map) conversionService.convert(foo, TypeDescriptor .valueOf(Map.class), new TypeDescriptor(getClass().getField("genericMap"))); assertEquals(FooEnum.BAR, map.get(1)); @@ -363,10 +453,10 @@ public class GenericConversionServiceTests { @Test public void convertMapToStringArray() throws Exception { + conversionService.addGenericConverter(Map.class, Object[].class, new MapToArrayConverter(conversionService)); Map foo = new LinkedHashMap(); foo.put("1", "BAR"); foo.put("2", "BAZ"); - conversionService.addConverterFactory(new StringToNumberConverterFactory()); String[] result = conversionService.convert(foo, String[].class); assertEquals("1=BAR", result[0]); assertEquals("2=BAZ", result[1]); @@ -374,19 +464,67 @@ public class GenericConversionServiceTests { @Test public void convertMapToStringArrayWithElementConversion() throws Exception { + conversionService.addGenericConverter(Map.class, Object[].class, new MapToArrayConverter(conversionService)); + conversionService.addConverter(new ObjectToStringConverter()); Map foo = new LinkedHashMap(); foo.put(1, FooEnum.BAR); foo.put(2, FooEnum.BAZ); - conversionService.addConverter(new ObjectToStringConverter()); String[] result = (String[]) conversionService.convert(foo, new TypeDescriptor(getClass() .getField("genericMap")), TypeDescriptor.valueOf(String[].class)); assertEquals("1=BAR", result[0]); assertEquals("2=BAZ", result[1]); } + @Test + public void convertMapToString() { + conversionService.addGenericConverter(Map.class, Object.class, new MapToObjectConverter(conversionService)); + Map foo = new LinkedHashMap(); + foo.put("1", "BAR"); + foo.put("2", "BAZ"); + String result = conversionService.convert(foo, String.class); + assertEquals("1=BAR 2=BAZ", result); + } + + @Test + public void convertMapToStringWithConversion() throws Exception { + conversionService.addGenericConverter(Map.class, Object.class, new MapToObjectConverter(conversionService)); + Map foo = new LinkedHashMap(); + foo.put(1, FooEnum.BAR); + foo.put(2, FooEnum.BAZ); + conversionService.addConverter(new ObjectToStringConverter()); + String result = (String) conversionService.convert(foo, new TypeDescriptor(getClass().getField("genericMap")), + TypeDescriptor.valueOf(String.class)); + assertEquals("1=BAR 2=BAZ", result); + } + + @Test + public void convertMapToObject() { + conversionService.addGenericConverter(Map.class, Object.class, new MapToObjectConverter(conversionService)); + Map foo = new LinkedHashMap(); + foo.put(1L, 1L); + foo.put(2L, 2L); + Long result = conversionService.convert(foo, Long.class); + assertEquals(new Long(1), result); + } + + public Map genericMap2 = new HashMap(); + + @Test + public void convertMapToObjectWithConversion() throws Exception { + conversionService.addGenericConverter(Map.class, Object.class, new MapToObjectConverter(conversionService)); + conversionService.addConverterFactory(new NumberToNumberConverterFactory()); + Map foo = new LinkedHashMap(); + foo.put(1L, 1L); + foo.put(2L, 2L); + Integer result = (Integer) conversionService.convert(foo, + new TypeDescriptor(getClass().getField("genericMap2")), TypeDescriptor.valueOf(Integer.class)); + assertEquals(new Integer(1), result); + } + @Test public void convertStringToArray() { - conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); String[] result = conversionService.convert("1,2,3", String[].class); assertEquals(3, result.length); assertEquals("1", result[0]); @@ -396,6 +534,8 @@ public class GenericConversionServiceTests { @Test public void convertStringToArrayWithElementConversion() { + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); Integer[] result = conversionService.convert("1,2,3", Integer[].class); assertEquals(3, result.length); @@ -406,14 +546,35 @@ public class GenericConversionServiceTests { @Test public void convertEmptyStringToArray() { - conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); String[] result = conversionService.convert("", String[].class); assertEquals(0, result.length); } + @Test + public void convertObjectToArray() { + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); + Object[] result = conversionService.convert(3L, Object[].class); + assertEquals(1, result.length); + assertEquals(3L, result[0]); + } + + @Test + public void convertObjectToArrayWithElementConversion() { + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); + conversionService.addConverterFactory(new NumberToNumberConverterFactory()); + Integer[] result = conversionService.convert(3L, Integer[].class); + assertEquals(1, result.length); + assertEquals(new Integer(3), result[0]); + } + @Test public void convertStringToCollection() { - conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter( + conversionService)); List result = conversionService.convert("1,2,3", List.class); assertEquals(3, result.size()); assertEquals("1", result.get(0)); @@ -423,6 +584,8 @@ public class GenericConversionServiceTests { @Test public void convertStringToCollectionWithElementConversion() throws Exception { + conversionService.addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); List result = (List) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericList"))); @@ -434,13 +597,16 @@ public class GenericConversionServiceTests { @Test public void convertEmptyStringToCollection() { - conversionService.addConverterFactory(new StringToNumberConverterFactory()); - String[] result = conversionService.convert("", String[].class); - assertEquals(0, result.length); + conversionService.addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter( + conversionService)); + Collection result = conversionService.convert("", Collection.class); + assertEquals(0, result.size()); } @Test public void convertObjectToCollection() { + conversionService.addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter( + conversionService)); List result = (List) conversionService.convert(3L, List.class); assertEquals(1, result.size()); assertEquals(3L, result.get(0)); @@ -448,6 +614,8 @@ public class GenericConversionServiceTests { @Test public void convertObjectToCollectionWithElementConversion() throws Exception { + conversionService.addGenericConverter(Object.class, Collection.class, new ObjectToCollectionConverter( + conversionService)); conversionService.addConverterFactory(new NumberToNumberConverterFactory()); List result = (List) conversionService.convert(3L, TypeDescriptor.valueOf(Long.class), new TypeDescriptor(getClass().getField("genericList"))); @@ -455,56 +623,9 @@ public class GenericConversionServiceTests { assertEquals(new Integer(3), result.get(0)); } - @Test - public void convertObjectToArray() { - Object[] result = conversionService.convert(3L, Object[].class); - assertEquals(1, result.length); - assertEquals(3L, result[0]); - } - - @Test - public void convertObjectToArrayWithElementConversion() { - conversionService.addConverterFactory(new NumberToNumberConverterFactory()); - Integer[] result = conversionService.convert(3L, Integer[].class); - assertEquals(1, result.length); - assertEquals(new Integer(3), result[0]); - } - - @Test - public void convertObjectToMap() { - Map result = conversionService.convert("foo=bar bar=baz", Map.class); - assertEquals("bar", result.get("foo")); - assertEquals("baz", result.get("bar")); - } - - @Test - public void convertObjectToMapWithConversion() throws Exception { - conversionService.addConverterFactory(new NumberToNumberConverterFactory()); - Map result = (Map) conversionService.convert(1L, TypeDescriptor.valueOf(Integer.class), new TypeDescriptor( - getClass().getField("genericMap2"))); - assertEquals(new Long(1), result.get(1L)); - } - - @Test - public void convertStringArrayToMap() { - Map result = conversionService.convert(new String[] { "foo=bar", "bar=baz", "baz=boop" }, Map.class); - assertEquals("bar", result.get("foo")); - assertEquals("baz", result.get("bar")); - assertEquals("boop", result.get("baz")); - } - - @Test - public void convertStringArrayToMapWithElementConversion() throws Exception { - conversionService.addConverterFactory(new StringToNumberConverterFactory()); - conversionService.addConverterFactory(new StringToEnumConverterFactory()); - Map result = (Map) conversionService.convert(new String[] { "1=BAR", "2=BAZ" }, TypeDescriptor - .valueOf(String[].class), new TypeDescriptor(getClass().getField("genericMap"))); - assertEquals(FooEnum.BAR, result.get(1)); - assertEquals(FooEnum.BAZ, result.get(2)); - } - @Test public void convertStringToMap() { + conversionService.addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(conversionService)); Map result = conversionService.convert("foo=bar bar=baz baz=boop", Map.class); assertEquals("bar", result.get("foo")); assertEquals("baz", result.get("bar")); @@ -513,6 +634,7 @@ public class GenericConversionServiceTests { @Test public void convertStringToMapWithElementConversion() throws Exception { + conversionService.addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(conversionService)); conversionService.addConverterFactory(new StringToNumberConverterFactory()); conversionService.addConverterFactory(new StringToEnumConverterFactory()); Map result = (Map) conversionService.convert("1=BAR 2=BAZ", TypeDescriptor.valueOf(String.class), @@ -522,49 +644,26 @@ public class GenericConversionServiceTests { } @Test - public void convertMapToString() { - Map foo = new LinkedHashMap(); - foo.put("1", "BAR"); - foo.put("2", "BAZ"); - String result = conversionService.convert(foo, String.class); - assertEquals("1=BAR 2=BAZ", result); - } - - @Test - public void convertMapToStringWithConversion() throws Exception { - Map foo = new LinkedHashMap(); - foo.put(1, FooEnum.BAR); - foo.put(2, FooEnum.BAZ); - conversionService.addConverter(new ObjectToStringConverter()); - String result = (String) conversionService.convert(foo, new TypeDescriptor(getClass().getField("genericMap")), - TypeDescriptor.valueOf(String.class)); - assertEquals("1=BAR 2=BAZ", result); - } - - @Test - public void convertMapToObject() { - Map foo = new LinkedHashMap(); - foo.put(1L, 1L); - foo.put(2L, 2L); - Long result = conversionService.convert(foo, Long.class); - assertEquals(new Long(1), result); + public void convertObjectToMap() { + conversionService.addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(conversionService)); + Map result = conversionService.convert("foo=bar bar=baz", Map.class); + assertEquals("bar", result.get("foo")); + assertEquals("baz", result.get("bar")); } - public Map genericMap2 = new HashMap(); - @Test - public void convertMapToObjectWithConversion() throws Exception { - Map foo = new LinkedHashMap(); - foo.put(1L, 1L); - foo.put(2L, 2L); + public void convertObjectToMapWithConversion() throws Exception { + conversionService.addGenericConverter(Object.class, Map.class, new ObjectToMapConverter(conversionService)); conversionService.addConverterFactory(new NumberToNumberConverterFactory()); - Integer result = (Integer) conversionService.convert(foo, - new TypeDescriptor(getClass().getField("genericMap2")), TypeDescriptor.valueOf(Integer.class)); - assertEquals(new Integer(1), result); + Map result = (Map) conversionService.convert(1L, TypeDescriptor.valueOf(Integer.class), new TypeDescriptor( + getClass().getField("genericMap2"))); + assertEquals(new Long(1), result.get(1L)); } @Test public void genericConverterDelegatingBackToConversionServiceConverterNotFound() { + conversionService.addGenericConverter(Object.class, Object[].class, new ObjectToArrayConverter( + conversionService)); try { conversionService.convert("1", Integer[].class); } catch (ConversionFailedException e) { -- GitLab