提交 1ee4ac1b 编写于 作者: K Keith Donald

string to map converters

上级 dedecf7a
...@@ -182,6 +182,7 @@ public class GenericConversionService implements ConversionService, ConverterReg ...@@ -182,6 +182,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
* Hook to initialize the "generic" converters that require the full TypeDescriptor context to perform their conversion operations. * Hook to initialize the "generic" converters that require the full TypeDescriptor context to perform their conversion operations.
*/ */
protected void initGenericConverters() { protected void initGenericConverters() {
addGenericConverter(String[].class, Map.class, new StringArrayToMapGenericConverter(this));
addGenericConverter(Object[].class, Object[].class, new ArrayToArrayGenericConverter(this)); addGenericConverter(Object[].class, Object[].class, new ArrayToArrayGenericConverter(this));
addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionGenericConverter(this)); addGenericConverter(Object[].class, Collection.class, new ArrayToCollectionGenericConverter(this));
addGenericConverter(Object[].class, String.class, new ArrayToStringGenericConverter(this)); addGenericConverter(Object[].class, String.class, new ArrayToStringGenericConverter(this));
...@@ -193,6 +194,7 @@ public class GenericConversionService implements ConversionService, ConverterReg ...@@ -193,6 +194,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this)); addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this));
addGenericConverter(String.class, Object[].class, new StringToArrayGenericConverter(this)); addGenericConverter(String.class, Object[].class, new StringToArrayGenericConverter(this));
addGenericConverter(String.class, Collection.class, new StringToCollectionGenericConverter(this)); addGenericConverter(String.class, Collection.class, new StringToCollectionGenericConverter(this));
addGenericConverter(String.class, Map.class, new StringToMapGenericConverter(this));
addGenericConverter(Object.class, Object[].class, new ObjectToArrayGenericConverter(this)); addGenericConverter(Object.class, Object[].class, new ObjectToArrayGenericConverter(this));
addGenericConverter(Object.class, Collection.class, new ObjectToCollectionGenericConverter(this)); addGenericConverter(Object.class, Collection.class, new ObjectToCollectionGenericConverter(this));
} }
......
/**
*
*/
package org.springframework.core.convert.support;
import static org.springframework.core.convert.support.ConversionUtils.invokeConverter;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
class MapEntryConverter {
private GenericConverter keyConverter;
private GenericConverter valueConverter;
private TypeDescriptor sourceKeyType;
private TypeDescriptor sourceValueType;
private TypeDescriptor targetKeyType;
private TypeDescriptor targetValueType;
public MapEntryConverter(TypeDescriptor sourceKeyType, TypeDescriptor sourceValueType, TypeDescriptor targetKeyType,
TypeDescriptor targetValueType, boolean keysCompatible, boolean valuesCompatible,
GenericConversionService conversionService) {
if (sourceKeyType != TypeDescriptor.NULL && targetKeyType != TypeDescriptor.NULL && !keysCompatible) {
this.keyConverter = conversionService.getConverter(sourceKeyType, targetKeyType);
if (this.keyConverter == null) {
throw new ConverterNotFoundException(sourceKeyType, targetKeyType);
}
this.sourceKeyType = sourceKeyType;
this.targetKeyType = targetKeyType;
}
if (sourceValueType != TypeDescriptor.NULL && targetValueType != TypeDescriptor.NULL && !valuesCompatible) {
this.valueConverter = conversionService.getConverter(sourceValueType, targetValueType);
if (this.valueConverter == null) {
throw new ConverterNotFoundException(sourceValueType, targetValueType);
}
this.targetKeyType = targetKeyType;
this.targetValueType = targetValueType;
}
}
public Object convertKey(Object sourceKey) {
if (sourceKey != null && this.keyConverter != null) {
return invokeConverter(this.keyConverter, sourceKey, this.sourceKeyType, this.targetKeyType);
} else {
return sourceKey;
}
}
public Object convertValue(Object sourceValue) {
if (sourceValue != null && this.valueConverter != null) {
return invokeConverter(this.valueConverter, sourceValue, this.sourceValueType, this.targetValueType);
} else {
return sourceValue;
}
}
}
\ No newline at end of file
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
import static org.springframework.core.convert.support.ConversionUtils.invokeConverter;
import java.util.Map; import java.util.Map;
import org.springframework.core.CollectionFactory; import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
final class MapToMapGenericConverter implements GenericConverter { final class MapToMapGenericConverter implements GenericConverter {
...@@ -20,13 +18,13 @@ final class MapToMapGenericConverter implements GenericConverter { ...@@ -20,13 +18,13 @@ final class MapToMapGenericConverter implements GenericConverter {
Map sourceMap = (Map) source; Map sourceMap = (Map) source;
TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor(); TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor();
TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor(); TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor();
if (targetKeyType == null && targetValueType == null) { if (targetKeyType == TypeDescriptor.NULL && targetValueType == TypeDescriptor.NULL) {
return compatibleMapWithoutEntryConversion(sourceMap, targetType); return compatibleMapWithoutEntryConversion(sourceMap, targetType);
} }
TypeDescriptor[] sourceEntryTypes = getMapEntryTypes(sourceMap); TypeDescriptor[] sourceEntryTypes = getMapEntryTypes(sourceMap);
TypeDescriptor sourceKeyType = sourceEntryTypes[0]; TypeDescriptor sourceKeyType = sourceEntryTypes[0];
TypeDescriptor sourceValueType = sourceEntryTypes[1]; TypeDescriptor sourceValueType = sourceEntryTypes[1];
if (sourceKeyType == null && sourceValueType == null) { if (sourceKeyType == TypeDescriptor.NULL && sourceValueType == TypeDescriptor.NULL) {
return compatibleMapWithoutEntryConversion(sourceMap, targetType); return compatibleMapWithoutEntryConversion(sourceMap, targetType);
} }
boolean keysCompatible = false; boolean keysCompatible = false;
...@@ -44,7 +42,9 @@ final class MapToMapGenericConverter implements GenericConverter { ...@@ -44,7 +42,9 @@ final class MapToMapGenericConverter implements GenericConverter {
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()) { for (Object entry : sourceMap.entrySet()) {
Map.Entry sourceMapEntry = (Map.Entry) entry; Map.Entry sourceMapEntry = (Map.Entry) entry;
targetMap.put(converter.convertKey(sourceMapEntry.getKey()), converter.convertValue(sourceMapEntry.getValue())); Object targetKey = converter.convertKey(sourceMapEntry.getKey());
Object targetValue = converter.convertValue(sourceMapEntry.getValue());
targetMap.put(targetKey, targetValue);
} }
return targetMap; return targetMap;
} }
...@@ -79,57 +79,4 @@ final class MapToMapGenericConverter implements GenericConverter { ...@@ -79,57 +79,4 @@ final class MapToMapGenericConverter implements GenericConverter {
} }
} }
private static class MapEntryConverter {
private GenericConverter keyConverter;
private GenericConverter valueConverter;
private TypeDescriptor sourceKeyType;
private TypeDescriptor sourceValueType;
private TypeDescriptor targetKeyType;
private TypeDescriptor targetValueType;
public MapEntryConverter(TypeDescriptor sourceKeyType, TypeDescriptor sourceValueType, TypeDescriptor targetKeyType,
TypeDescriptor targetValueType, boolean keysCompatible, boolean valuesCompatible,
GenericConversionService conversionService) {
if (sourceKeyType != TypeDescriptor.NULL && targetKeyType != TypeDescriptor.NULL && !keysCompatible) {
this.keyConverter = conversionService.getConverter(sourceKeyType, targetKeyType);
if (this.keyConverter == null) {
throw new ConverterNotFoundException(sourceKeyType, targetKeyType);
}
this.sourceKeyType = sourceKeyType;
this.targetKeyType = targetKeyType;
}
if (sourceValueType != TypeDescriptor.NULL && targetValueType != TypeDescriptor.NULL && !valuesCompatible) {
this.valueConverter = conversionService.getConverter(sourceValueType, targetValueType);
if (this.valueConverter == null) {
throw new ConverterNotFoundException(sourceValueType, targetValueType);
}
this.targetKeyType = targetKeyType;
this.targetValueType = targetValueType;
}
}
public Object convertKey(Object sourceKey) {
if (sourceKey != null && this.keyConverter != null) {
return invokeConverter(this.keyConverter, sourceKey, this.sourceKeyType, this.targetKeyType);
} else {
return sourceKey;
}
}
public Object convertValue(Object sourceValue) {
if (sourceValue != null && this.valueConverter != null) {
return invokeConverter(this.valueConverter, sourceValue, this.sourceValueType, this.targetValueType);
} else {
return sourceValue;
}
}
}
} }
/*
* 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;
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.convert.support;
import org.springframework.core.convert.TypeDescriptor;
final class StringToMapGenericConverter implements GenericConverter {
private final StringArrayToMapGenericConverter converter;
public StringToMapGenericConverter(GenericConversionService conversionService) {
this.converter = new StringArrayToMapGenericConverter(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);
}
}
\ No newline at end of file
...@@ -206,7 +206,7 @@ public class GenericConversionServiceTests { ...@@ -206,7 +206,7 @@ public class GenericConversionServiceTests {
String result = conversionService.convert(new String[0], String.class); String result = conversionService.convert(new String[0], String.class);
assertEquals("", result); assertEquals("", result);
} }
@Test @Test
public void convertArrayToObject() { public void convertArrayToObject() {
Object[] array = new Object[] { 3L }; Object[] array = new Object[] { 3L };
...@@ -272,7 +272,8 @@ public class GenericConversionServiceTests { ...@@ -272,7 +272,8 @@ public class GenericConversionServiceTests {
public void convertCollectionToStringWithElementConversion() throws Exception { public void convertCollectionToStringWithElementConversion() throws Exception {
conversionService.addConverter(new ObjectToStringConverter()); conversionService.addConverter(new ObjectToStringConverter());
List<Integer> list = Arrays.asList(new Integer[] { 3, 5 }); List<Integer> list = Arrays.asList(new Integer[] { 3, 5 });
String result = (String) conversionService.convert(list, new TypeDescriptor(getClass().getField("genericList")), TypeDescriptor.valueOf(String.class)); String result = (String) conversionService.convert(list,
new TypeDescriptor(getClass().getField("genericList")), TypeDescriptor.valueOf(String.class));
assertEquals("3,5", result); assertEquals("3,5", result);
} }
...@@ -302,8 +303,8 @@ public class GenericConversionServiceTests { ...@@ -302,8 +303,8 @@ public class GenericConversionServiceTests {
conversionService.addConverterFactory(new StringToEnumConverterFactory()); conversionService.addConverterFactory(new StringToEnumConverterFactory());
Map<String, FooEnum> map = (Map<String, FooEnum>) conversionService.convert(foo, TypeDescriptor Map<String, FooEnum> map = (Map<String, FooEnum>) conversionService.convert(foo, TypeDescriptor
.valueOf(Map.class), new TypeDescriptor(getClass().getField("genericMap"))); .valueOf(Map.class), new TypeDescriptor(getClass().getField("genericMap")));
assertEquals(map.get(1), FooEnum.BAR); assertEquals(FooEnum.BAR, map.get(1));
assertEquals(map.get(2), FooEnum.BAZ); assertEquals(FooEnum.BAZ, map.get(2));
} }
@Test @Test
...@@ -346,7 +347,8 @@ public class GenericConversionServiceTests { ...@@ -346,7 +347,8 @@ public class GenericConversionServiceTests {
@Test @Test
public void convertStringToCollectionWithElementConversion() throws Exception { public void convertStringToCollectionWithElementConversion() throws Exception {
conversionService.addConverterFactory(new StringToNumberConverterFactory()); conversionService.addConverterFactory(new StringToNumberConverterFactory());
List result = (List) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericList"))); List result = (List) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
new TypeDescriptor(getClass().getField("genericList")));
assertEquals(3, result.size()); assertEquals(3, result.size());
assertEquals(new Integer(1), result.get(0)); assertEquals(new Integer(1), result.get(0));
assertEquals(new Integer(2), result.get(1)); assertEquals(new Integer(2), result.get(1));
...@@ -391,6 +393,42 @@ public class GenericConversionServiceTests { ...@@ -391,6 +393,42 @@ public class GenericConversionServiceTests {
assertEquals(new Integer(3), result[0]); assertEquals(new Integer(3), result[0]);
} }
@Test
public void convertStringArrayToMap() {
Map result = conversionService.convert(new String[] { "foo=bar", "bar=baz", "baz=boop" }, Map.class);
assertEquals("bar", result.get("foo"));
assertEquals("baz", result.get("bar"));
assertEquals("boop", result.get("baz"));
}
@Test
public void convertStringArrayToMapWithElementConversion() throws Exception {
conversionService.addConverterFactory(new StringToNumberConverterFactory());
conversionService.addConverterFactory(new StringToEnumConverterFactory());
Map result = (Map) conversionService.convert(new String[] { "1=BAR", "2=BAZ" }, TypeDescriptor
.valueOf(String[].class), new TypeDescriptor(getClass().getField("genericMap")));
assertEquals(FooEnum.BAR, result.get(1));
assertEquals(FooEnum.BAZ, result.get(2));
}
@Test
public void convertStringToMap() {
Map result = conversionService.convert("foo=bar bar=baz baz=boop", Map.class);
assertEquals("bar", result.get("foo"));
assertEquals("baz", result.get("bar"));
assertEquals("boop", result.get("baz"));
}
@Test
public void convertStringToMapWithElementConversion() throws Exception {
conversionService.addConverterFactory(new StringToNumberConverterFactory());
conversionService.addConverterFactory(new StringToEnumConverterFactory());
Map result = (Map) conversionService.convert("1=BAR 2=BAZ", TypeDescriptor
.valueOf(String.class), new TypeDescriptor(getClass().getField("genericMap")));
assertEquals(FooEnum.BAR, result.get(1));
assertEquals(FooEnum.BAZ, result.get(2));
}
@Test @Test
public void genericConverterDelegatingBackToConversionServiceConverterNotFound() { public void genericConverterDelegatingBackToConversionServiceConverterNotFound() {
try { try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册