map to map generic converter
This commit is contained in:
parent
ac6e26388f
commit
8e800f0322
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue