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 9bac79190e1..a43b709f133 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 @@ -281,7 +281,7 @@ public class TypeDescriptor { */ public TypeDescriptor getElementTypeDescriptor(Object element) { TypeDescriptor elementType = getElementTypeDescriptor(); - return (elementType != TypeDescriptor.UNKNOWN ? elementType : forObject(element)); + return (!TypeDescriptor.UNKNOWN.equals(elementType) ? elementType : forObject(element)); } /** diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java index 27203af2e40..e86619a306e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 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. @@ -49,7 +49,8 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter { } public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { - return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService); + return ConversionUtils.canConvertElements( + sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService); } @SuppressWarnings("unchecked") @@ -58,12 +59,21 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter { return null; } int length = Array.getLength(source); - Collection target = CollectionFactory.createCollection(targetType.getType(), length); - for (int i = 0; i < length; i++) { - Object sourceElement = Array.get(source, i); - Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(sourceElement)); - target.add(targetElement); + Collection target = CollectionFactory.createCollection(targetType.getType(), length); + if (targetType.getElementTypeDescriptor() == null) { + for (int i = 0; i < length; i++) { + Object sourceElement = Array.get(source, i); + target.add(sourceElement); + } } + else { + for (int i = 0; i < length; i++) { + Object sourceElement = Array.get(source, i); + Object targetElement = this.conversionService.convert(sourceElement, + sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor()); + target.add(targetElement); + } + } return target; } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java index efc89e852ab..9104dc0d74d 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java @@ -49,7 +49,8 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert } public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { - return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), conversionService); + return ConversionUtils.canConvertElements( + sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService); } @SuppressWarnings("unchecked") @@ -57,15 +58,25 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert if (source == null) { return null; } + boolean copyRequired = !targetType.getType().isInstance(source); Collection sourceCollection = (Collection) source; - Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); - for (Object sourceElement : sourceCollection) { - Object targetElement = this.conversionService.convert(sourceElement, - sourceType.getElementTypeDescriptor(sourceElement), - targetType.getElementTypeDescriptor(sourceElement)); - target.add(targetElement); + Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); + if (targetType.getElementTypeDescriptor() == null) { + for (Object element : sourceCollection) { + target.add(element); + } } - return target; + else { + for (Object sourceElement : sourceCollection) { + Object targetElement = this.conversionService.convert(sourceElement, + sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor()); + target.add(targetElement); + if (sourceElement != targetElement) { + copyRequired = true; + } + } + } + return (copyRequired ? target : source); } } 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 1b731d1826a..7a008ec075b 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 @@ -148,7 +148,8 @@ public class GenericConversionService implements ConversionService, ConverterReg Assert.isTrue(source == null || sourceType.getObjectType().isInstance(source)); GenericConverter converter = getConverter(sourceType, targetType); if (converter == null) { - if (source == null || targetType.getObjectType().isInstance(source)) { + if (source == null || + (sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source))) { return source; } else { diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java index 6b1cf4ec5b3..3c1483aee4e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java @@ -49,8 +49,7 @@ final class MapToMapConverter implements ConditionalGenericConverter { } public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { - return this.conversionService.canConvert(sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()) && - this.conversionService.canConvert(sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor()); + return canConvertKey(sourceType, targetType) && canConvertValue(sourceType, targetType); } @SuppressWarnings("unchecked") @@ -58,21 +57,46 @@ final class MapToMapConverter implements ConditionalGenericConverter { if (source == null) { return null; } - Map sourceMap = (Map) source; - Map targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size()); - for (Object entry : sourceMap.entrySet()) { - Map.Entry sourceMapEntry = (Map.Entry) entry; - Object sourceKey = sourceMapEntry.getKey(); - Object sourceValue = sourceMapEntry.getValue(); - Object targetKey = this.conversionService.convert(sourceKey, - sourceType.getMapKeyTypeDescriptor(sourceKey), - targetType.getMapKeyTypeDescriptor(sourceKey)); - Object targetValue = this.conversionService.convert(sourceValue, - sourceType.getMapValueTypeDescriptor(sourceValue), - targetType.getMapValueTypeDescriptor(sourceValue)); + boolean copyRequired = !targetType.getType().isInstance(source); + Map sourceMap = (Map) source; + Map targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size()); + for (Map.Entry entry : sourceMap.entrySet()) { + Object sourceKey = entry.getKey(); + Object sourceValue = entry.getValue(); + Object targetKey = convertKey(sourceKey, sourceType, targetType.getMapKeyTypeDescriptor()); + Object targetValue = convertValue(sourceValue, sourceType, targetType.getMapValueTypeDescriptor()); targetMap.put(targetKey, targetValue); + if (sourceKey != targetKey || sourceValue != targetValue) { + copyRequired = true; + } } - return targetMap; + return (copyRequired ? targetMap : sourceMap); } - + + // internal helpers + + private boolean canConvertKey(TypeDescriptor sourceType, TypeDescriptor targetType) { + return ConversionUtils.canConvertElements(sourceType.getMapKeyTypeDescriptor(), + targetType.getMapKeyTypeDescriptor(), this.conversionService); + } + + private boolean canConvertValue(TypeDescriptor sourceType, TypeDescriptor targetType) { + return ConversionUtils.canConvertElements(sourceType.getMapValueTypeDescriptor(), + targetType.getMapValueTypeDescriptor(), this.conversionService); + } + + private Object convertKey(Object sourceKey, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (targetType == null) { + return sourceKey; + } + return this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor(sourceKey), targetType); + } + + private Object convertValue(Object sourceValue, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (targetType == null) { + return sourceValue; + } + return this.conversionService.convert(sourceValue, sourceType.getMapValueTypeDescriptor(sourceValue), targetType); + } + } diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java new file mode 100644 index 00000000000..6811893be8c --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java @@ -0,0 +1,295 @@ +/* + * Copyright 2002-2011 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 java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +import static org.junit.Assert.*; + +/** + * @author Keith Donald + */ +public class CollectionToCollectionConverterTests { + + private GenericConversionService conversionService = new GenericConversionService(); + + @Before + public void setUp() { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + } + + @Test + public void scalarList() throws Exception { + List list = new ArrayList(); + list.add("9"); + list.add("37"); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarListTarget")); + assertFalse(conversionService.canConvert(sourceType, targetType)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + List result = (List) conversionService.convert(list, sourceType, targetType); + assertFalse(list.equals(result)); + assertEquals((Integer) 9, result.get(0)); + assertEquals((Integer) 37, result.get(1)); + } + + public ArrayList scalarListTarget; + + @Test + public void emptyListToList() throws Exception { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List list = new ArrayList(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyListTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertEquals(list, conversionService.convert(list, sourceType, targetType)); + } + + public List emptyListTarget; + + @Test + public void emptyListToListDifferentTargetType() throws Exception { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List list = new ArrayList(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyListDifferentTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + LinkedList result = (LinkedList) conversionService.convert(list, sourceType, targetType); + assertEquals(LinkedList.class, result.getClass()); + assertTrue(result.isEmpty()); + } + + public LinkedList emptyListDifferentTarget; + + @Test + public void collectionToObjectInteraction() throws Exception { + List> list = new ArrayList>(); + list.add(Arrays.asList("9", "12")); + list.add(Arrays.asList("37", "23")); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(List.class, List.class)); + assertSame(list, conversionService.convert(list, List.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void arrayCollectionToObjectInteraction() throws Exception { + List[] array = new List[2]; + array[0] = Arrays.asList("9", "12"); + array[1] = Arrays.asList("37", "23"); + conversionService.addConverter(new ArrayToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(String[].class, List.class)); + assertEquals(Arrays.asList(array), conversionService.convert(array, List.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void objectToCollection() throws Exception { + List> list = new ArrayList>(); + list.add(Arrays.asList("9", "12")); + list.add(Arrays.asList("37", "23")); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverter(new ObjectToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("objectToCollection")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + List>> result = (List>>) conversionService.convert(list, sourceType, targetType); + assertEquals((Integer)9, result.get(0).get(0).get(0)); + assertEquals((Integer)12, result.get(0).get(1).get(0)); + assertEquals((Integer)37, result.get(1).get(0).get(0)); + assertEquals((Integer)23, result.get(1).get(1).get(0)); + } + + public List>> objectToCollection; + + @Test + @SuppressWarnings("unchecked") + public void stringToCollection() throws Exception { + List> list = new ArrayList>(); + list.add(Arrays.asList("9,12")); + list.add(Arrays.asList("37,23")); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverter(new StringToCollectionConverter(conversionService)); + conversionService.addConverter(new ObjectToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("objectToCollection")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + List>> result = (List>>) conversionService.convert(list, sourceType, targetType); + assertEquals((Integer)9, result.get(0).get(0).get(0)); + assertEquals((Integer)12, result.get(0).get(0).get(1)); + assertEquals((Integer)37, result.get(1).get(0).get(0)); + assertEquals((Integer)23, result.get(1).get(0).get(1)); + } + + @Test + public void differentImpls() throws Exception { + List resources = new ArrayList(); + resources.add(new ClassPathResource("test")); + resources.add(new FileSystemResource("test")); + resources.add(new TestResource()); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test + public void mixedInNulls() throws Exception { + List resources = new ArrayList(); + resources.add(new ClassPathResource("test")); + resources.add(null); + resources.add(new FileSystemResource("test")); + resources.add(new TestResource()); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test + public void allNulls() throws Exception { + List resources = new ArrayList(); + resources.add(null); + resources.add(null); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test(expected=ConverterNotFoundException.class) + public void elementTypesNotConvertible() throws Exception { + List resources = new ArrayList(); + resources.add(null); + resources.add(null); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("strings")); + assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + public List strings; + + @Test(expected=ConversionFailedException.class) + public void nothingInCommon() throws Exception { + List resources = new ArrayList(); + resources.add(new ClassPathResource("test")); + resources.add(3); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + public List resources; + + public static abstract class BaseResource implements Resource { + + public InputStream getInputStream() throws IOException { + return null; + } + + public boolean exists() { + return false; + } + + public boolean isReadable() { + return false; + } + + public boolean isOpen() { + return false; + } + + public URL getURL() throws IOException { + return null; + } + + public URI getURI() throws IOException { + return null; + } + + public File getFile() throws IOException { + return null; + } + + public long contentLength() throws IOException { + return 0; + } + + public long lastModified() throws IOException { + return 0; + } + + public Resource createRelative(String relativePath) throws IOException { + return null; + } + + public String getFilename() { + return null; + } + + public String getDescription() { + return null; + } + } + + public static class TestResource extends BaseResource { + + } + + @Test + public void convertEmptyVector_shouldReturnEmptyArrayList() { + Vector vector = new Vector(); + vector.add("Element"); + testCollectionConversionToArrayList(vector); + } + + @Test + public void convertNonEmptyVector_shouldReturnNonEmptyArrayList() { + Vector vector = new Vector(); + vector.add("Element"); + testCollectionConversionToArrayList(vector); + } + + @SuppressWarnings("rawtypes") + private void testCollectionConversionToArrayList(Collection aSource) { + Object myConverted = (new CollectionToCollectionConverter(new GenericConversionService())).convert( + aSource, TypeDescriptor.forObject(aSource), TypeDescriptor.forObject(new ArrayList())); + assertTrue(myConverted instanceof ArrayList); + assertEquals(aSource.size(), ((ArrayList) myConverted).size()); + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java new file mode 100644 index 00000000000..2100b3790c0 --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java @@ -0,0 +1,186 @@ +/* + * Copyright 2002-2011 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 java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; + +import static org.junit.Assert.*; + +public class MapToMapConverterTests { + + private GenericConversionService conversionService = new GenericConversionService(); + + @Before + public void setUp() { + conversionService.addConverter(new MapToMapConverter(conversionService)); + } + + @Test + public void scalarMap() throws Exception { + Map map = new HashMap(); + map.put("1", "9"); + map.put("2", "37"); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget")); + assertFalse(conversionService.canConvert(sourceType, targetType)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map result = (Map) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals((Integer) 9, result.get(1)); + assertEquals((Integer) 37, result.get(2)); + } + + public Map scalarMapTarget; + + @Test + public void scalarMapNotGenericTarget() throws Exception { + Map map = new HashMap(); + map.put("1", "9"); + map.put("2", "37"); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void scalarMapNotGenericSourceField() throws Exception { + Map map = new HashMap(); + map.put("1", "9"); + map.put("2", "37"); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("notGenericMapSource")); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(map, sourceType, targetType); + } catch (ConversionFailedException e) { + assertTrue(e.getCause() instanceof ConverterNotFoundException); + } + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map result = (Map) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals((Integer) 9, result.get(1)); + assertEquals((Integer) 37, result.get(2)); + } + + public Map notGenericMapSource; + + @Test + public void collectionMap() throws Exception { + Map> map = new HashMap>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget")); + assertFalse(conversionService.canConvert(sourceType, targetType)); + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map> result = (Map>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals(Arrays.asList(9, 12), result.get(1)); + assertEquals(Arrays.asList(37, 23), result.get(2)); + } + + public Map> collectionMapTarget; + + @Test + public void collectionMapSourceTarget() throws Exception { + Map> map = new HashMap>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget")); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget")); + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map> result = (Map>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals(Arrays.asList(9, 12), result.get(1)); + assertEquals(Arrays.asList(37, 23), result.get(2)); + } + + public Map> sourceCollectionMapTarget; + + @Test + public void collectionMapNotGenericTarget() throws Exception { + Map> map = new HashMap>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void collectionMapNotGenericTargetCollectionToObjectInteraction() throws Exception { + Map> map = new HashMap>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void emptyMap() throws Exception { + Map map = new HashMap(); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertSame(map, conversionService.convert(map, sourceType, targetType)); + } + + public Map emptyMapTarget; + + @Test + public void emptyMapNoTargetGenericInfo() throws Exception { + Map map = new HashMap(); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void emptyMapDifferentTargetImplType() throws Exception { + Map map = new HashMap(); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapDifferentTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + LinkedHashMap result = (LinkedHashMap) conversionService.convert(map, sourceType, targetType); + assertEquals(map, result); + assertEquals(LinkedHashMap.class, result.getClass()); + } + + public LinkedHashMap emptyMapDifferentTarget; + +}