From 7a6dafd5ad99e16dc20a116d3ee83836b959db76 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Wed, 23 Sep 2009 18:25:04 +0000 Subject: [PATCH] completed generic converter implementation --- .../core/convert/TypeDescriptor.java | 100 ++++++++++-------- .../support/ArrayToArrayGenericConverter.java | 26 +---- ...r.java => ArrayToMapGenericConverter.java} | 18 ++-- .../ArrayToObjectGenericConverter.java | 25 +---- .../ArrayToStringGenericConverter.java | 69 ------------ .../CollectionToMapGenericConverter.java | 96 +++++++++++++++++ .../CollectionToObjectGenericConverter.java | 70 +++++++++--- .../CollectionToStringGenericConverter.java | 75 ------------- .../core/convert/support/ConversionUtils.java | 27 +++++ .../support/GenericConversionService.java | 18 ++-- .../support/MapToArrayGenericConverter.java | 39 +++++++ ...a => MapToCollectionGenericConverter.java} | 41 +++---- .../support/MapToMapGenericConverter.java | 12 ++- .../support/MapToObjectGenericConverter.java | 100 ++++++++++++++++++ .../ObjectToArrayGenericConverter.java | 37 +++++-- .../ObjectToCollectionGenericConverter.java | 42 ++++++-- .../support/ObjectToMapGenericConverter.java | 64 +++++++++++ .../StringArrayToMapGenericConverter.java | 84 --------------- .../StringToArrayGenericConverter.java | 53 ---------- .../StringToCollectionGenericConverter.java | 58 ---------- .../GenericConversionServiceTests.java | 42 ++++++++ 21 files changed, 595 insertions(+), 501 deletions(-) rename org.springframework.core/src/main/java/org/springframework/core/convert/support/{StringToMapGenericConverter.java => ArrayToMapGenericConverter.java} (64%) delete mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToStringGenericConverter.java create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToMapGenericConverter.java delete mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringGenericConverter.java create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToArrayGenericConverter.java rename org.springframework.core/src/main/java/org/springframework/core/convert/support/{MapToStringArrayGenericConverter.java => MapToCollectionGenericConverter.java} (56%) create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToObjectGenericConverter.java create mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToMapGenericConverter.java delete mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMapGenericConverter.java delete mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayGenericConverter.java delete mode 100644 org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionGenericConverter.java 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 42b2cb3b428..4d9cf47844d 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 @@ -44,6 +44,8 @@ public class TypeDescriptor { private Class type; + private TypeDescriptor elementType; + private MethodParameter methodParameter; private Field field; @@ -88,6 +90,11 @@ public class TypeDescriptor { private TypeDescriptor() { } + private TypeDescriptor(Class collectionType, TypeDescriptor elementType) { + this.type = collectionType; + this.elementType = elementType; + } + /** * Return the wrapped MethodParameter, if any. *

Note: Either MethodParameter or Field is available. @@ -113,14 +120,11 @@ public class TypeDescriptor { public Class getType() { if (this.type != null) { return this.type; - } - else if (this.field != null) { + } else if (this.field != null) { return this.field.getType(); - } - else if (this.methodParameter != null) { + } else if (this.methodParameter != null) { return this.methodParameter.getParameterType(); - } - else { + } else { return null; } } @@ -134,6 +138,15 @@ public class TypeDescriptor { return type != null ? ClassUtils.resolvePrimitiveIfNecessary(type) : type; } + /** + * Does the underyling declared type equal the type provided? + * @param type the type to test against + */ + public boolean typeEquals(Class type) { + Class thisType = getType(); + return thisType != null ? thisType.equals(type) : false; + } + /** * Returns the name of this type; the fully qualified classname. */ @@ -141,8 +154,7 @@ public class TypeDescriptor { Class type = getType(); if (type != null) { return getType().getName(); - } - else { + } else { return null; } } @@ -167,22 +179,24 @@ public class TypeDescriptor { * Returns null if the type is neither an array or collection. */ public Class getElementType() { - if (isArray()) { - return getArrayComponentType(); - } - else if (isCollection()) { - return getCollectionElementType(); - } - else { - return null; - } + return getElementTypeDescriptor().getType(); } /** * Return the element type as a type descriptor. */ public TypeDescriptor getElementTypeDescriptor() { - return TypeDescriptor.valueOf(getElementType()); + if (elementType != null) { + return elementType; + } else { + if (isArray()) { + return TypeDescriptor.valueOf(getArrayComponentType()); + } else if (isCollection()) { + return TypeDescriptor.valueOf(getCollectionElementType()); + } else { + return TypeDescriptor.NULL; + } + } } /** @@ -191,7 +205,7 @@ public class TypeDescriptor { public boolean isMap() { return isTypeAssignableTo(Map.class); } - + /** * Is this descriptor for a map where the key type and value type are known? */ @@ -206,11 +220,9 @@ public class TypeDescriptor { public Class getMapKeyType() { if (this.field != null) { return GenericCollectionTypeResolver.getMapKeyFieldType(field); - } - else if (this.methodParameter != null) { + } else if (this.methodParameter != null) { return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter); - } - else { + } else { return null; } } @@ -222,11 +234,9 @@ public class TypeDescriptor { public Class getMapValueType() { if (this.field != null) { return GenericCollectionTypeResolver.getMapValueFieldType(this.field); - } - else if (this.methodParameter != null) { + } else if (this.methodParameter != null) { return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter); - } - else { + } else { return null; } } @@ -254,11 +264,9 @@ public class TypeDescriptor { this.cachedFieldAnnotations = this.field.getAnnotations(); } return this.cachedFieldAnnotations; - } - else if (this.methodParameter != null) { + } else if (this.methodParameter != null) { return this.methodParameter.getMethod().getAnnotations(); - } - else { + } else { return new Annotation[0]; } } @@ -300,10 +308,9 @@ public class TypeDescriptor { if (isArray()) { // TODO should properly handle multi dimensional arrays stringValue.append(getArrayComponentType().getName()).append("[]"); - } - else { + } else { Class clazz = getType(); - if (clazz==null) { + if (clazz == null) { return "null"; } stringValue.append(clazz.getName()); @@ -312,8 +319,7 @@ public class TypeDescriptor { if (collectionType != null) { stringValue.append("<").append(collectionType.getName()).append(">"); } - } - else if (isMap()) { + } else if (isMap()) { Class keyType = getMapKeyType(); Class valType = getMapValueType(); if (keyType != null && valType != null) { @@ -325,7 +331,6 @@ public class TypeDescriptor { return stringValue.toString(); } - // internal helpers private Class getArrayComponentType() { @@ -336,21 +341,18 @@ public class TypeDescriptor { private Class getCollectionElementType() { if (this.type != null) { return GenericCollectionTypeResolver.getCollectionType((Class) this.type); - } - else if (this.field != null) { + } else if (this.field != null) { return GenericCollectionTypeResolver.getCollectionFieldType(this.field); - } - else { + } else { return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter); } } - + private boolean isTypeAssignableTo(Class clazz) { Class type = getType(); return (type != null && ClassUtils.isAssignable(clazz, type)); } - // static factory methods /** @@ -371,4 +373,16 @@ public class TypeDescriptor { return (object == null ? NULL : valueOf(object.getClass())); } + public String toString() { + if (this == TypeDescriptor.NULL) { + return "[TypeDescriptor.NULL]"; + } else { + return "[TypeDescriptor type=" + getType().getName() + "]"; + } + } + + public static TypeDescriptor collection(Class type, TypeDescriptor elementType) { + return new TypeDescriptor(type, elementType); + } + } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArrayGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArrayGenericConverter.java index 66c145217a1..df994119b08 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArrayGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToArrayGenericConverter.java @@ -15,38 +15,20 @@ */ package org.springframework.core.convert.support; -import static org.springframework.core.convert.support.ConversionUtils.invokeConverter; +import static org.springframework.core.convert.support.ConversionUtils.asList; -import java.lang.reflect.Array; - -import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; final class ArrayToArrayGenericConverter implements GenericConverter { - private final GenericConversionService conversionService; + private final GenericConverter helperConverter; public ArrayToArrayGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; + this.helperConverter = new CollectionToArrayGenericConverter(conversionService); } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - if (sourceType.isAssignableTo(targetType)) { - return source; - } - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); - Object target = Array.newInstance(targetElementType.getType(), Array.getLength(source)); - GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetElementType); - if (converter == null) { - throw new ConverterNotFoundException(sourceElementType, targetElementType); - } - for (int i = 0; i < Array.getLength(target); i++) { - Object sourceElement = Array.get(source, i); - Object targetElement = invokeConverter(converter, sourceElement, sourceElementType, targetElementType); - Array.set(target, i, targetElement); - } - return target; + return this.helperConverter.convert(asList(source), sourceType, targetType); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMapGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToMapGenericConverter.java similarity index 64% rename from org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMapGenericConverter.java rename to org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToMapGenericConverter.java index c5d04b1212f..4d194e398b0 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToMapGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToMapGenericConverter.java @@ -15,20 +15,20 @@ */ package org.springframework.core.convert.support; +import static org.springframework.core.convert.support.ConversionUtils.asList; + import org.springframework.core.convert.TypeDescriptor; -final class StringToMapGenericConverter implements GenericConverter { +final class ArrayToMapGenericConverter implements GenericConverter { - private final StringArrayToMapGenericConverter converter; - - public StringToMapGenericConverter(GenericConversionService conversionService) { - this.converter = new StringArrayToMapGenericConverter(conversionService); + private final GenericConverter helperConverter; + + public ArrayToMapGenericConverter(GenericConversionService conversionService) { + this.helperConverter = new CollectionToMapGenericConverter(conversionService); } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - String string = (String) source; - String[] properties = string.split(" "); - return this.converter.convert(properties, TypeDescriptor.valueOf(String[].class), targetType); + return this.helperConverter.convert(asList(source), sourceType, targetType); } -} \ No newline at end of file +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToObjectGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToObjectGenericConverter.java index c1f31c87c4f..bdca07e3a66 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToObjectGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToObjectGenericConverter.java @@ -15,37 +15,20 @@ */ package org.springframework.core.convert.support; -import static org.springframework.core.convert.support.ConversionUtils.invokeConverter; +import static org.springframework.core.convert.support.ConversionUtils.asList; -import java.lang.reflect.Array; - -import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; final class ArrayToObjectGenericConverter implements GenericConverter { - private final GenericConversionService conversionService; + private CollectionToObjectGenericConverter helperConverter; public ArrayToObjectGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; + this.helperConverter = new CollectionToObjectGenericConverter(conversionService); } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - int length = Array.getLength(source); - if (length == 0) { - return null; - } else { - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - if (sourceElementType.isAssignableTo(targetType)) { - return Array.get(source, 0); - } else { - GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); - if (converter == null) { - throw new ConverterNotFoundException(sourceElementType, targetType); - } - return invokeConverter(converter, Array.get(source, 0), sourceElementType, targetType); - } - } + return this.helperConverter.convert(asList(source), sourceType, targetType); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToStringGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToStringGenericConverter.java deleted file mode 100644 index d283e73202d..00000000000 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToStringGenericConverter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 static org.springframework.core.convert.support.ConversionUtils.invokeConverter; - -import java.lang.reflect.Array; - -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.core.convert.TypeDescriptor; - -final class ArrayToStringGenericConverter implements GenericConverter { - - private static final String DELIMITER = ","; - - private final GenericConversionService conversionService; - - public ArrayToStringGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; - } - - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - int length = Array.getLength(source); - if (length == 0) { - return ""; - } else { - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - if (sourceElementType.isAssignableTo(targetType)) { - StringBuilder string = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i > 0) { - string.append(DELIMITER); - } - string.append(Array.get(source, i)); - } - return string.toString(); - } else { - GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); - if (converter == null) { - throw new ConverterNotFoundException(sourceElementType, targetType); - } - StringBuilder string = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i > 0) { - string.append(DELIMITER); - } - Object sourceElement = Array.get(source, i); - Object targetElement = invokeConverter(converter, sourceElement, sourceElementType, targetType); - string.append(targetElement); - } - return string.toString(); - } - } - } - -} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToMapGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToMapGenericConverter.java new file mode 100644 index 00000000000..5947008ce5d --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToMapGenericConverter.java @@ -0,0 +1,96 @@ +/* + * 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 static org.springframework.core.convert.support.ConversionUtils.getElementType; + +import java.util.Collection; +import java.util.Map; + +import org.springframework.core.CollectionFactory; +import org.springframework.core.convert.TypeDescriptor; + +final class CollectionToMapGenericConverter implements GenericConverter { + + private final GenericConversionService conversionService; + + public CollectionToMapGenericConverter(GenericConversionService conversionService) { + this.conversionService = conversionService; + } + + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + Collection sourceCollection = (Collection) source; + TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); + if (sourceElementType == TypeDescriptor.NULL) { + sourceElementType = getElementType(sourceCollection); + } + TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor(); + TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor(); + boolean keysCompatible = false; + if (sourceElementType == TypeDescriptor.NULL || targetKeyType == TypeDescriptor.NULL + || sourceElementType.isAssignableTo(targetKeyType)) { + keysCompatible = true; + } + boolean valuesCompatible = false; + if (sourceElementType == TypeDescriptor.NULL || targetValueType == TypeDescriptor.NULL + || sourceElementType.isAssignableTo(targetValueType)) { + valuesCompatible = true; + } + if (keysCompatible && valuesCompatible) { + Map target = CollectionFactory.createMap(targetType.getType(), sourceCollection.size()); + if (sourceElementType.typeEquals(String.class)) { + for (Object element : sourceCollection) { + String[] property = parseProperty((String) element); + target.put(property[0], property[1]); + } + } else { + for (Object element : sourceCollection) { + target.put(element, element); + } + } + return target; + } else { + Map target = CollectionFactory.createMap(targetType.getType(), sourceCollection.size()); + MapEntryConverter converter = new MapEntryConverter(sourceElementType, sourceElementType, targetKeyType, + targetValueType, keysCompatible, valuesCompatible, conversionService); + if (sourceElementType.typeEquals(String.class)) { + for (Object element : sourceCollection) { + String[] property = parseProperty((String) element); + Object targetKey = converter.convertKey(property[0]); + Object targetValue = converter.convertValue(property[1]); + target.put(targetKey, targetValue); + } + } else { + for (Object element : sourceCollection) { + Object targetKey = converter.convertKey(element); + Object targetValue = converter.convertValue(element); + target.put(targetKey, targetValue); + } + } + return target; + } + } + + private String[] parseProperty(String string) { + String[] property = string.split("="); + if (property.length < 2) { + throw new IllegalArgumentException("Invalid String property '" + property + + "'; properties should be in the format name=value"); + } + return property; + } + +} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectGenericConverter.java index c869933b26b..881063cf24b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectGenericConverter.java @@ -15,6 +15,7 @@ */ package org.springframework.core.convert.support; +import static org.springframework.core.convert.support.ConversionUtils.getElementType; import static org.springframework.core.convert.support.ConversionUtils.invokeConverter; import java.util.Collection; @@ -24,6 +25,8 @@ import org.springframework.core.convert.TypeDescriptor; final class CollectionToObjectGenericConverter implements GenericConverter { + private static final String DELIMITER = ","; + private final GenericConversionService conversionService; public CollectionToObjectGenericConverter(GenericConversionService conversionService) { @@ -33,21 +36,60 @@ final class CollectionToObjectGenericConverter implements GenericConverter { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Collection sourceCollection = (Collection) source; if (sourceCollection.size() == 0) { - return null; - } else { - Object firstElement = sourceCollection.iterator().next(); - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - if (sourceElementType == TypeDescriptor.NULL && firstElement != null) { - sourceElementType = TypeDescriptor.valueOf(firstElement.getClass()); - } - if (sourceElementType == TypeDescriptor.NULL || sourceElementType.isAssignableTo(targetType)) { - return firstElement; + if (targetType.typeEquals(String.class)) { + return ""; } else { - GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); - if (converter == null) { - throw new ConverterNotFoundException(sourceElementType, targetType); - } - return invokeConverter(converter, firstElement, sourceElementType, targetType); + return null; + } + } else { + if (targetType.typeEquals(String.class)) { + TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); + if (sourceElementType == TypeDescriptor.NULL) { + sourceElementType = getElementType(sourceCollection); + } + if (sourceElementType == TypeDescriptor.NULL || sourceElementType.isAssignableTo(targetType)) { + StringBuilder string = new StringBuilder(); + int i = 0; + for (Object element : sourceCollection) { + if (i > 0) { + string.append(DELIMITER); + } + string.append(element); + i++; + } + return string.toString(); + } else { + GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); + if (converter == null) { + throw new ConverterNotFoundException(sourceElementType, targetType); + } + StringBuilder string = new StringBuilder(); + int i = 0; + for (Object sourceElement : sourceCollection) { + if (i > 0) { + string.append(DELIMITER); + } + Object targetElement = invokeConverter(converter, sourceElement, sourceElementType, targetType); + string.append(targetElement); + i++; + } + return string.toString(); + } + } else { + Object firstElement = sourceCollection.iterator().next(); + TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); + if (sourceElementType == TypeDescriptor.NULL && firstElement != null) { + sourceElementType = TypeDescriptor.valueOf(firstElement.getClass()); + } + if (sourceElementType == TypeDescriptor.NULL || sourceElementType.isAssignableTo(targetType)) { + return firstElement; + } else { + GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); + if (converter == null) { + throw new ConverterNotFoundException(sourceElementType, targetType); + } + return invokeConverter(converter, firstElement, sourceElementType, targetType); + } } } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringGenericConverter.java deleted file mode 100644 index 913ad883f36..00000000000 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringGenericConverter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 static org.springframework.core.convert.support.ConversionUtils.getElementType; -import static org.springframework.core.convert.support.ConversionUtils.invokeConverter; - -import java.util.Collection; - -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.core.convert.TypeDescriptor; - -final class CollectionToStringGenericConverter implements GenericConverter { - - private static final String DELIMITER = ","; - - private final GenericConversionService conversionService; - - public CollectionToStringGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; - } - - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - Collection sourceCollection = (Collection) source; - if (sourceCollection.size() == 0) { - return ""; - } else { - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - if (sourceElementType == TypeDescriptor.NULL) { - sourceElementType = getElementType(sourceCollection); - } - if (sourceElementType == TypeDescriptor.NULL || sourceElementType.isAssignableTo(targetType)) { - StringBuilder string = new StringBuilder(); - int i = 0; - for (Object element : sourceCollection) { - if (i > 0) { - string.append(DELIMITER); - } - string.append(element); - i++; - } - return string.toString(); - } else { - GenericConverter converter = this.conversionService.getConverter(sourceElementType, targetType); - if (converter == null) { - throw new ConverterNotFoundException(sourceElementType, targetType); - } - StringBuilder string = new StringBuilder(); - int i = 0; - for (Object sourceElement : sourceCollection) { - if (i > 0) { - string.append(DELIMITER); - } - Object targetElement = invokeConverter(converter, sourceElement, sourceElementType, targetType); - string.append(targetElement); - i++; - } - return string.toString(); - } - } - } -} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java index 3d8fa6b34e4..6114c04b115 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java @@ -15,7 +15,11 @@ */ package org.springframework.core.convert.support; +import java.lang.reflect.Array; +import java.util.AbstractList; import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.TypeDescriptor; @@ -39,4 +43,27 @@ final class ConversionUtils { } return TypeDescriptor.NULL; } + + + public static List asList(Object array) { + return new ArrayList(array); + } + + private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { + + private Object array; + + ArrayList(Object array) { + this.array = array; + } + + public int size() { + return Array.getLength(array); + } + + public Object get(int index) { + return Array.get(array, index); + } + + } } 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 ec31ba448e2..bec8a250119 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 @@ -182,27 +182,21 @@ public class GenericConversionService implements ConversionService, ConverterReg * Hook to initialize the "generic" converters that require the full TypeDescriptor context to perform their conversion operations. */ protected void initGenericConverters() { - addGenericConverter(String[].class, Map.class, new StringArrayToMapGenericConverter(this)); addGenericConverter(Object[].class, Object[].class, new ArrayToArrayGenericConverter(this)); addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionGenericConverter(this)); - addGenericConverter(Object[].class, String.class, new ArrayToStringGenericConverter(this)); + addGenericConverter(Object[].class, Map.class, new ArrayToMapGenericConverter(this)); addGenericConverter(Object[].class, Object.class, new ArrayToObjectGenericConverter(this)); - // TODO Collection->Map addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionGenericConverter(this)); addGenericConverter(Collection.class, Object[].class, new CollectionToArrayGenericConverter(this)); - addGenericConverter(Collection.class, String.class, new CollectionToStringGenericConverter(this)); + addGenericConverter(Collection.class, Map.class, new CollectionToMapGenericConverter(this)); addGenericConverter(Collection.class, Object.class, new CollectionToObjectGenericConverter(this)); addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this)); - addGenericConverter(Map.class, String[].class, new MapToStringArrayGenericConverter(this)); - // TODO Map->Collection - // TODO Map->String - // TODO Map->Object - addGenericConverter(String.class, Object[].class, new StringToArrayGenericConverter(this)); - addGenericConverter(String.class, Collection.class, new StringToCollectionGenericConverter(this)); - addGenericConverter(String.class, Map.class, new StringToMapGenericConverter(this)); + addGenericConverter(Map.class, Object[].class, new MapToArrayGenericConverter(this)); + addGenericConverter(Map.class, Collection.class, new MapToCollectionGenericConverter(this)); + addGenericConverter(Map.class, Object.class, new MapToObjectGenericConverter(this)); addGenericConverter(Object.class, Object[].class, new ObjectToArrayGenericConverter(this)); addGenericConverter(Object.class, Collection.class, new ObjectToCollectionGenericConverter(this)); - // TODO Object->Map + addGenericConverter(Object.class, Map.class, new ObjectToMapGenericConverter(this)); } /** diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToArrayGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToArrayGenericConverter.java new file mode 100644 index 00000000000..cb5d49bdcab --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToArrayGenericConverter.java @@ -0,0 +1,39 @@ +/* + * 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 java.util.List; + +import org.springframework.core.convert.TypeDescriptor; + +final class MapToArrayGenericConverter implements GenericConverter { + + private final GenericConverter mapToCollectionHelperConverter; + + private final GenericConverter collectionToArrayHelperConverter; + + public MapToArrayGenericConverter(GenericConversionService conversionService) { + this.mapToCollectionHelperConverter = new MapToCollectionGenericConverter(conversionService); + this.collectionToArrayHelperConverter = new CollectionToArrayGenericConverter(conversionService); + } + + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + TypeDescriptor collectionType = TypeDescriptor.collection(List.class, targetType.getElementTypeDescriptor()); + Object collection = this.mapToCollectionHelperConverter.convert(source, sourceType, collectionType); + return this.collectionToArrayHelperConverter.convert(collection, collectionType, targetType); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToStringArrayGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToCollectionGenericConverter.java similarity index 56% rename from org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToStringArrayGenericConverter.java rename to org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToCollectionGenericConverter.java index 4f710981717..f6a6c2b9567 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToStringArrayGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToCollectionGenericConverter.java @@ -15,44 +15,49 @@ */ package org.springframework.core.convert.support; -import java.lang.reflect.Array; +import java.util.Collection; import java.util.Map; +import org.springframework.core.CollectionFactory; import org.springframework.core.convert.TypeDescriptor; -final class MapToStringArrayGenericConverter implements GenericConverter { +final class MapToCollectionGenericConverter implements GenericConverter { private final GenericConversionService conversionService; - public MapToStringArrayGenericConverter(GenericConversionService conversionService) { + public MapToCollectionGenericConverter(GenericConversionService conversionService) { this.conversionService = conversionService; } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Map sourceMap = (Map) source; TypeDescriptor sourceKeyType = sourceType.getMapKeyTypeDescriptor(); - TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor(); + TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor(); TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); boolean keysCompatible = false; - if (sourceKeyType.isAssignableTo(targetElementType)) { + if (targetElementType == TypeDescriptor.NULL || sourceKeyType.isAssignableTo(targetElementType)) { keysCompatible = true; } boolean valuesCompatible = false; - if (sourceValueType.isAssignableTo(targetElementType)) { + if (targetElementType == TypeDescriptor.NULL || sourceValueType.isAssignableTo(targetElementType)) { valuesCompatible = true; - } - Object array = Array.newInstance(targetElementType.getType(), sourceMap.size()); - MapEntryConverter converter = new MapEntryConverter(sourceKeyType, sourceValueType, targetElementType, targetElementType, keysCompatible, valuesCompatible, conversionService); - int i = 0; - for (Object entry : sourceMap.entrySet()) { - Map.Entry mapEntry = (Map.Entry) entry; - Object key = mapEntry.getKey(); - Object value = mapEntry.getValue(); - String property = converter.convertKey(key) + "=" + converter.convertValue(value); - Array.set(array, i, property); - i++; } - return array; + Collection target = CollectionFactory.createCollection(targetType.getType(), sourceMap.size()); + MapEntryConverter converter = new MapEntryConverter(sourceKeyType, sourceValueType, targetElementType, + targetElementType, keysCompatible, valuesCompatible, conversionService); + if (targetElementType.getType().equals(String.class)) { + for (Object entry : sourceMap.entrySet()) { + Map.Entry mapEntry = (Map.Entry) entry; + String property = converter.convertKey(mapEntry.getKey()) + "=" + + converter.convertValue(mapEntry.getValue()); + target.add(property); + } + } else { + for (Object value : sourceMap.values()) { + target.add(value); + } + } + return target; } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapGenericConverter.java index cce7d6327bf..11dda0168fa 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapGenericConverter.java @@ -1,6 +1,5 @@ package org.springframework.core.convert.support; - import java.util.Map; import org.springframework.core.CollectionFactory; @@ -28,22 +27,25 @@ final class MapToMapGenericConverter implements GenericConverter { return compatibleMapWithoutEntryConversion(sourceMap, targetType); } boolean keysCompatible = false; - if (sourceKeyType != TypeDescriptor.NULL && targetKeyType != TypeDescriptor.NULL && sourceKeyType.isAssignableTo(targetKeyType)) { + if (sourceKeyType != TypeDescriptor.NULL && targetKeyType != TypeDescriptor.NULL + && sourceKeyType.isAssignableTo(targetKeyType)) { keysCompatible = true; } boolean valuesCompatible = false; - if (sourceValueType != TypeDescriptor.NULL && targetValueType != TypeDescriptor.NULL && sourceValueType.isAssignableTo(targetValueType)) { + if (sourceValueType != TypeDescriptor.NULL && targetValueType != TypeDescriptor.NULL + && sourceValueType.isAssignableTo(targetValueType)) { valuesCompatible = true; } if (keysCompatible && valuesCompatible) { return compatibleMapWithoutEntryConversion(sourceMap, targetType); } Map targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size()); - MapEntryConverter converter = new MapEntryConverter(sourceKeyType, sourceValueType, targetKeyType, targetValueType, keysCompatible, valuesCompatible, conversionService); + MapEntryConverter converter = new MapEntryConverter(sourceKeyType, sourceValueType, targetKeyType, + targetValueType, keysCompatible, valuesCompatible, conversionService); for (Object entry : sourceMap.entrySet()) { Map.Entry sourceMapEntry = (Map.Entry) entry; Object targetKey = converter.convertKey(sourceMapEntry.getKey()); - Object targetValue = converter.convertValue(sourceMapEntry.getValue()); + Object targetValue = converter.convertValue(sourceMapEntry.getValue()); targetMap.put(targetKey, targetValue); } return targetMap; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToObjectGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToObjectGenericConverter.java new file mode 100644 index 00000000000..a088a96cea2 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToObjectGenericConverter.java @@ -0,0 +1,100 @@ +/* + * 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 java.util.Map; + +import org.springframework.core.convert.TypeDescriptor; + +final class MapToObjectGenericConverter implements GenericConverter { + + private static final String DELIMITER = " "; + + private final GenericConversionService conversionService; + + public MapToObjectGenericConverter(GenericConversionService conversionService) { + this.conversionService = conversionService; + } + + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + Map sourceMap = (Map) source; + if (sourceMap.size() == 0) { + if (targetType.typeEquals(String.class)) { + return ""; + } else { + return null; + } + } else { + if (targetType.typeEquals(String.class)) { + TypeDescriptor sourceKeyType = sourceType.getMapKeyTypeDescriptor(); + TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor(); + boolean keysCompatible = false; + if (sourceKeyType == TypeDescriptor.NULL || sourceKeyType.isAssignableTo(targetType)) { + keysCompatible = true; + } + boolean valuesCompatible = false; + if (sourceValueType == TypeDescriptor.NULL || sourceValueType.isAssignableTo(targetType)) { + valuesCompatible = true; + } + if (keysCompatible && valuesCompatible) { + StringBuilder string = new StringBuilder(); + int i = 0; + for (Object entry : sourceMap.entrySet()) { + Map.Entry mapEntry = (Map.Entry) entry; + if (i > 0) { + string.append(DELIMITER); + } + String property = mapEntry.getKey() + "=" + mapEntry.getValue(); + string.append(property); + i++; + } + return string.toString(); + } else { + MapEntryConverter converter = new MapEntryConverter(sourceKeyType, sourceValueType, targetType, targetType, + keysCompatible, valuesCompatible, conversionService); + StringBuilder string = new StringBuilder(); + int i = 0; + for (Object entry : sourceMap.entrySet()) { + Map.Entry mapEntry = (Map.Entry) entry; + if (i > 0) { + string.append(DELIMITER); + } + Object key = converter.convertKey(mapEntry.getKey()); + Object value = converter.convertValue(mapEntry.getValue()); + String property = key + "=" + value; + string.append(property); + i++; + } + return string.toString(); + } + } else { + TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor(); + boolean valuesCompatible = false; + if (sourceValueType == TypeDescriptor.NULL || sourceValueType.isAssignableTo(targetType)) { + valuesCompatible = true; + } + if (valuesCompatible) { + return sourceMap.values().iterator().next(); + } else { + MapEntryConverter converter = new MapEntryConverter(sourceValueType, sourceValueType, targetType, targetType, + true, valuesCompatible, conversionService); + Object value = sourceMap.values().iterator().next(); + return converter.convertValue(value); + } + } + } + } +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayGenericConverter.java index f442646d7b1..ff2806cf1fe 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayGenericConverter.java @@ -21,6 +21,7 @@ import java.lang.reflect.Array; import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.StringUtils; final class ObjectToArrayGenericConverter implements GenericConverter { @@ -32,17 +33,35 @@ final class ObjectToArrayGenericConverter implements GenericConverter { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); - Object target = Array.newInstance(targetElementType.getType(), 1); - if (sourceType.isAssignableTo(targetElementType)) { - Array.set(target, 0, source); - } else { - GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); - if (converter == null) { - throw new ConverterNotFoundException(sourceType, targetElementType); + if (sourceType.typeEquals(String.class)) { + String string = (String) source; + String[] fields = StringUtils.commaDelimitedListToStringArray(string); + if (sourceType.isAssignableTo(targetElementType)) { + return fields; + } else { + Object target = Array.newInstance(targetElementType.getType(), fields.length); + GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); + if (converter == null) { + throw new ConverterNotFoundException(sourceType, targetElementType); + } + for (int i = 0; i < fields.length; i++) { + Array.set(target, i, invokeConverter(converter, fields[i], sourceType, targetElementType)); + } + return target; } - Array.set(target, 0, invokeConverter(converter, source, sourceType, targetElementType)); + } else { + Object target = Array.newInstance(targetElementType.getType(), 1); + if (sourceType.isAssignableTo(targetElementType)) { + Array.set(target, 0, source); + } else { + GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); + if (converter == null) { + throw new ConverterNotFoundException(sourceType, targetElementType); + } + Array.set(target, 0, invokeConverter(converter, source, sourceType, targetElementType)); + } + return target; } - return target; } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionGenericConverter.java index f64ffd2419d..10208f4ee69 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionGenericConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionGenericConverter.java @@ -22,6 +22,7 @@ import java.util.Collection; import org.springframework.core.CollectionFactory; import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.StringUtils; final class ObjectToCollectionGenericConverter implements GenericConverter { @@ -32,18 +33,41 @@ final class ObjectToCollectionGenericConverter implements GenericConverter { } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - Collection target = CollectionFactory.createCollection(targetType.getType(), 1); TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); - if (targetElementType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetElementType)) { - target.add(source); - } else { - GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); - if (converter == null) { - throw new ConverterNotFoundException(sourceType, targetElementType); + if (sourceType.typeEquals(String.class)) { + String string = (String) source; + String[] fields = StringUtils.commaDelimitedListToStringArray(string); + Collection target = CollectionFactory.createCollection(targetType.getType(), fields.length); + if (targetElementType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetElementType)) { + for (int i = 0; i < fields.length; i++) { + target.add(fields[i]); + } + } else { + GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); + if (converter == null) { + throw new ConverterNotFoundException(sourceType, targetElementType); + } + for (int i = 0; i < fields.length; i++) { + String sourceElement = fields[i]; + Object targetElement = invokeConverter(converter, sourceElement, sourceType, targetElementType); + target.add(targetElement); + } } - target.add(invokeConverter(converter, source, sourceType, targetElementType)); + return target; + + } else { + Collection target = CollectionFactory.createCollection(targetType.getType(), 1); + if (targetElementType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetElementType)) { + target.add(source); + } else { + GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); + if (converter == null) { + throw new ConverterNotFoundException(sourceType, targetElementType); + } + target.add(invokeConverter(converter, source, sourceType, targetElementType)); + } + return target; } - return target; } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToMapGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToMapGenericConverter.java new file mode 100644 index 00000000000..aa80dc1ec10 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToMapGenericConverter.java @@ -0,0 +1,64 @@ +/* + * 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 java.util.Map; + +import org.springframework.core.CollectionFactory; +import org.springframework.core.convert.TypeDescriptor; + +final class ObjectToMapGenericConverter implements GenericConverter { + + private final GenericConversionService conversionService; + + private final ArrayToMapGenericConverter helperConverter; + + public ObjectToMapGenericConverter(GenericConversionService conversionService) { + this.conversionService = conversionService; + this.helperConverter = new ArrayToMapGenericConverter(conversionService); + } + + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (sourceType.typeEquals(String.class)) { + String string = (String) source; + String[] properties = string.split(" "); + return this.helperConverter.convert(properties, TypeDescriptor.valueOf(String[].class), targetType); + } else { + Map target = CollectionFactory.createMap(targetType.getType(), 1); + TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor(); + TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor(); + boolean keysCompatible = false; + if (targetKeyType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetKeyType)) { + keysCompatible = true; + } + boolean valuesCompatible = false; + if (targetValueType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetValueType)) { + valuesCompatible = true; + } + if (keysCompatible && valuesCompatible) { + target.put(source, source); + } else { + MapEntryConverter converter = new MapEntryConverter(sourceType, sourceType, targetKeyType, + targetValueType, keysCompatible, valuesCompatible, conversionService); + Object key = converter.convertKey(source); + Object value = converter.convertValue(source); + target.put(key, value); + } + return target; + } + } + +} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMapGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMapGenericConverter.java deleted file mode 100644 index e19406d1586..00000000000 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringArrayToMapGenericConverter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 java.lang.reflect.Array; -import java.util.Map; - -import org.springframework.core.CollectionFactory; -import org.springframework.core.convert.TypeDescriptor; - -final class StringArrayToMapGenericConverter implements GenericConverter { - - private final GenericConversionService conversionService; - - public StringArrayToMapGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; - } - - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor(); - TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor(); - if (targetKeyType == TypeDescriptor.NULL && targetValueType == TypeDescriptor.NULL) { - return mapWithoutConversion(source, targetType); - } - TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor(); - boolean keysCompatible = false; - if (sourceElementType.isAssignableTo(targetKeyType)) { - keysCompatible = true; - } - boolean valuesCompatible = false; - if (sourceElementType.isAssignableTo(targetValueType)) { - valuesCompatible = true; - } - if (keysCompatible && valuesCompatible) { - return mapWithoutConversion(source, targetType); - } - int length = Array.getLength(source); - Map target = CollectionFactory.createMap(targetType.getType(), length); - MapEntryConverter converter = new MapEntryConverter(sourceElementType, sourceElementType, targetKeyType, targetValueType, keysCompatible, valuesCompatible, conversionService); - for (int i = 0; i < length; i++) { - String property = (String) Array.get(source, i); - String[] fields = property.split("="); - if (fields.length < 2) { - throw new IllegalArgumentException("Invalid String property '" + property - + "'; properties should be in the format name=value"); - } - Object targetKey = converter.convertKey(fields[0]); - Object targetValue = converter.convertValue(fields[1]); - target.put(targetKey, targetValue); - } - return target; - } - - private Map mapWithoutConversion(Object source, TypeDescriptor targetType) { - int length = Array.getLength(source); - Map target = CollectionFactory.createMap(targetType.getType(), length); - for (int i = 0; i < length; i++) { - String property = (String) Array.get(source, i); - String[] fields = property.split("="); - if (fields.length < 2) { - throw new IllegalArgumentException("Invalid String property '" + property - + "'; properties should be in the format name=value"); - } - String key = fields[0]; - String value = fields[1]; - target.put(key, value); - } - return target; - } - -} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayGenericConverter.java deleted file mode 100644 index 22f7699e0d8..00000000000 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayGenericConverter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 static org.springframework.core.convert.support.ConversionUtils.invokeConverter; - -import java.lang.reflect.Array; - -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.util.StringUtils; - -final class StringToArrayGenericConverter implements GenericConverter { - - private final GenericConversionService conversionService; - - public StringToArrayGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; - } - - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - String string = (String) source; - String[] fields = StringUtils.commaDelimitedListToStringArray(string); - TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); - if (sourceType.isAssignableTo(targetElementType)) { - return fields; - } else { - Object target = Array.newInstance(targetElementType.getType(), fields.length); - GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); - if (converter == null) { - throw new ConverterNotFoundException(sourceType, targetElementType); - } - for (int i = 0; i < fields.length; i++) { - Array.set(target, i, invokeConverter(converter, fields[i], sourceType, targetElementType)); - } - return target; - } - } - -} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionGenericConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionGenericConverter.java deleted file mode 100644 index b4018667268..00000000000 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionGenericConverter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 static org.springframework.core.convert.support.ConversionUtils.invokeConverter; - -import java.util.Collection; - -import org.springframework.core.CollectionFactory; -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.util.StringUtils; - -final class StringToCollectionGenericConverter implements GenericConverter { - - private final GenericConversionService conversionService; - - public StringToCollectionGenericConverter(GenericConversionService conversionService) { - this.conversionService = conversionService; - } - - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - String string = (String) source; - String[] fields = StringUtils.commaDelimitedListToStringArray(string); - Collection target = CollectionFactory.createCollection(targetType.getType(), 1); - TypeDescriptor targetElementType = targetType.getElementTypeDescriptor(); - if (targetElementType == TypeDescriptor.NULL || sourceType.isAssignableTo(targetElementType)) { - for (int i = 0; i < fields.length; i++) { - target.add(fields[i]); - } - } else { - GenericConverter converter = this.conversionService.getConverter(sourceType, targetElementType); - if (converter == null) { - throw new ConverterNotFoundException(sourceType, targetElementType); - } - for (int i = 0; i < fields.length; i++) { - String sourceElement = fields[i]; - Object targetElement = invokeConverter(converter, sourceElement, sourceType, targetElementType); - target.add(targetElement); - } - } - return target; - } - -} \ 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 9fd56fe004b..61a5f3a5774 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 @@ -453,6 +453,48 @@ public class GenericConversionServiceTests { assertEquals(FooEnum.BAZ, result.get(2)); } + @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 Map genericMap2 = new HashMap(); + + @Test + public void convertMapToObjectWithConversion() throws Exception { + Map foo = new LinkedHashMap(); + foo.put(1L, 1L); + foo.put(2L, 2L); + conversionService.addConverterFactory(new NumberToNumberConverterFactory()); + Integer result = (Integer) conversionService.convert(foo, + new TypeDescriptor(getClass().getField("genericMap2")), TypeDescriptor.valueOf(Integer.class)); + assertEquals(new Integer(1), result); + } + @Test public void genericConverterDelegatingBackToConversionServiceConverterNotFound() { try {