map to map generic converter

This commit is contained in:
Keith Donald 2009-09-18 14:30:23 +00:00
parent ac6e26388f
commit 8e800f0322
4 changed files with 139 additions and 20 deletions

View File

@ -38,42 +38,41 @@ class CollectionToCollectionGenericConverter implements GenericConverter {
public Object convert(Object source, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor targetType) {
Collection sourceCollection = (Collection) source; Collection sourceCollection = (Collection) source;
Object firstNotNullElement = getFirstNotNullElement(sourceCollection); Class targetElementType = targetType.getElementType();
if (firstNotNullElement == null) { if (targetElementType == null) {
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType); return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
} }
Class targetElementType = targetType.getElementType(); Class sourceElementType = getElementType(sourceCollection);
if (targetElementType == null || targetElementType.isAssignableFrom(firstNotNullElement.getClass())) { if (sourceElementType == null || targetElementType.isAssignableFrom(sourceElementType)) {
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType); return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
} }
Collection targetCollection = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); Collection targetCollection = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
GenericConverter elementConverter = conversionService.getConverter(firstNotNullElement.getClass(), TypeDescriptor targetElementTypeDescriptor = TypeDescriptor.valueOf(targetElementType);
TypeDescriptor.valueOf(targetElementType)); GenericConverter elementConverter = conversionService.getConverter(sourceElementType,
targetElementTypeDescriptor);
for (Object element : sourceCollection) { for (Object element : sourceCollection) {
targetCollection.add(elementConverter.convert(element, TypeDescriptor.valueOf(targetElementType))); targetCollection.add(elementConverter.convert(element, targetElementTypeDescriptor));
} }
return targetCollection; return targetCollection;
} }
private Class getElementType(Collection collection) {
for (Object element : collection) {
if (element != null) {
return element.getClass();
}
}
return null;
}
private Collection compatibleCollectionWithoutElementConversion(Collection source, TypeDescriptor targetType) { private Collection compatibleCollectionWithoutElementConversion(Collection source, TypeDescriptor targetType) {
if (targetType.getType().isAssignableFrom(source.getClass())) { if (targetType.getType().isAssignableFrom(source.getClass())) {
return source; return source;
} else { } else {
Collection target = CollectionFactory.createCollection(targetType.getType(), source.size()); Collection target = CollectionFactory.createCollection(targetType.getType(), source.size());
for (Object element : source) { target.addAll(source);
target.addAll(source);
}
return target; return target;
} }
} }
private Object getFirstNotNullElement(Collection collection) {
for (Object element : collection) {
if (element != null) {
return element;
}
}
return null;
}
} }

View File

@ -58,6 +58,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
public GenericConversionService() { public GenericConversionService() {
addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionGenericConverter(this)); addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionGenericConverter(this));
addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this));
} }
/** /**

View File

@ -0,0 +1,120 @@
package org.springframework.core.convert.support;
import java.util.Map;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.TypeDescriptor;
class MapToMapGenericConverter implements GenericConverter {
private GenericConversionService conversionService;
public MapToMapGenericConverter(GenericConversionService conversionService) {
this.conversionService = conversionService;
}
public Object convert(Object source, TypeDescriptor targetType) {
Map sourceMap = (Map) source;
Class targetKeyType = targetType.getMapKeyType();
Class targetValueType = targetType.getMapValueType();
if (targetKeyType == null && targetValueType == null) {
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
}
Class[] sourceEntryTypes = getMapEntryTypes(sourceMap);
Class sourceKeyType = sourceEntryTypes[0];
Class sourceValueType = sourceEntryTypes[1];
if (sourceKeyType == null && sourceValueType == null) {
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
}
boolean keysCompatible = false;
if (targetKeyType != null && sourceKeyType != null && targetKeyType.isAssignableFrom(sourceKeyType)) {
keysCompatible = true;
}
boolean valuesCompatible = false;
if (targetValueType != null && sourceValueType != null && targetValueType.isAssignableFrom(sourceValueType)) {
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);
for (Object entry : sourceMap.entrySet()) {
Map.Entry sourceMapEntry = (Map.Entry) entry;
targetMap.put(converter.convertKey(sourceMapEntry.getKey()), converter.convertValue(sourceMapEntry.getValue()));
}
return targetMap;
}
private Class[] getMapEntryTypes(Map sourceMap) {
Class keyType = null;
Class valueType = null;
for (Object entry : sourceMap.entrySet()) {
Map.Entry mapEntry = (Map.Entry) entry;
Object key = mapEntry.getKey();
if (keyType == null && key != null) {
keyType = key.getClass();
}
Object value = mapEntry.getValue();
if (valueType == null && value != null) {
valueType = value.getClass();
}
if (mapEntry.getKey() != null && mapEntry.getValue() != null) {
break;
}
}
return new Class[] { keyType, valueType };
}
private Map compatibleMapWithoutEntryConversion(Map source, TypeDescriptor targetType) {
if (targetType.getType().isAssignableFrom(source.getClass())) {
return source;
} else {
Map target = CollectionFactory.createMap(targetType.getType(), source.size());
target.putAll(source);
return target;
}
}
private static class MapEntryConverter {
private GenericConverter keyConverter;
private GenericConverter valueConverter;
private TypeDescriptor targetKeyTypeDescriptor;
private TypeDescriptor targetValueTypeDescriptor;
public MapEntryConverter(Class sourceKeyType, Class sourceValueType, Class targetKeyType,
Class targetValueType, boolean keysCompatible, boolean valuesCompatible,
GenericConversionService conversionService) {
if (sourceKeyType != null && targetKeyType != null && !keysCompatible) {
this.targetKeyTypeDescriptor = TypeDescriptor.valueOf(targetKeyType);
this.keyConverter = conversionService.getConverter(sourceKeyType, targetKeyTypeDescriptor);
}
if (sourceValueType != null && targetValueType != null && !valuesCompatible) {
this.targetValueTypeDescriptor = TypeDescriptor.valueOf(targetValueType);
this.valueConverter = conversionService.getConverter(sourceValueType, targetValueTypeDescriptor);
}
}
public Object convertKey(Object sourceKey) {
if (sourceKey != null && this.keyConverter != null) {
return this.keyConverter.convert(sourceKey, targetKeyTypeDescriptor);
} else {
return sourceKey;
}
}
public Object convertValue(Object sourceValue) {
if (sourceValue != null && this.valueConverter != null) {
return this.valueConverter.convert(sourceValue, targetValueTypeDescriptor);
} else {
return sourceValue;
}
}
}
}

View File

@ -230,7 +230,6 @@ public class GenericConversionServiceTests {
public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>(); public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>();
@Test @Test
@Ignore
public void convertMapToMap() throws Exception { public void convertMapToMap() throws Exception {
Map<String, String> foo = new HashMap<String, String>(); Map<String, String> foo = new HashMap<String, String>();
foo.put("1", "BAR"); foo.put("1", "BAR");