string to map converters
This commit is contained in:
parent
dedecf7ae9
commit
1ee4ac1b52
|
|
@ -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.
|
||||
*/
|
||||
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));
|
||||
|
|
@ -193,6 +194,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
|||
addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this));
|
||||
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(Object.class, Object[].class, new ObjectToArrayGenericConverter(this));
|
||||
addGenericConverter(Object.class, Collection.class, new ObjectToCollectionGenericConverter(this));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
package org.springframework.core.convert.support;
|
||||
|
||||
import static org.springframework.core.convert.support.ConversionUtils.invokeConverter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
final class MapToMapGenericConverter implements GenericConverter {
|
||||
|
|
@ -20,13 +18,13 @@ final class MapToMapGenericConverter implements GenericConverter {
|
|||
Map sourceMap = (Map) source;
|
||||
TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor();
|
||||
TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor();
|
||||
if (targetKeyType == null && targetValueType == null) {
|
||||
if (targetKeyType == TypeDescriptor.NULL && targetValueType == TypeDescriptor.NULL) {
|
||||
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
||||
}
|
||||
TypeDescriptor[] sourceEntryTypes = getMapEntryTypes(sourceMap);
|
||||
TypeDescriptor sourceKeyType = sourceEntryTypes[0];
|
||||
TypeDescriptor sourceValueType = sourceEntryTypes[1];
|
||||
if (sourceKeyType == null && sourceValueType == null) {
|
||||
if (sourceKeyType == TypeDescriptor.NULL && sourceValueType == TypeDescriptor.NULL) {
|
||||
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
||||
}
|
||||
boolean keysCompatible = false;
|
||||
|
|
@ -44,7 +42,9 @@ final class MapToMapGenericConverter implements GenericConverter {
|
|||
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()));
|
||||
Object targetKey = converter.convertKey(sourceMapEntry.getKey());
|
||||
Object targetValue = converter.convertValue(sourceMapEntry.getValue());
|
||||
targetMap.put(targetKey, targetValue);
|
||||
}
|
||||
return targetMap;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -206,7 +206,7 @@ public class GenericConversionServiceTests {
|
|||
String result = conversionService.convert(new String[0], String.class);
|
||||
assertEquals("", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void convertArrayToObject() {
|
||||
Object[] array = new Object[] { 3L };
|
||||
|
|
@ -272,7 +272,8 @@ public class GenericConversionServiceTests {
|
|||
public void convertCollectionToStringWithElementConversion() throws Exception {
|
||||
conversionService.addConverter(new ObjectToStringConverter());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -302,8 +303,8 @@ public class GenericConversionServiceTests {
|
|||
conversionService.addConverterFactory(new StringToEnumConverterFactory());
|
||||
Map<String, FooEnum> map = (Map<String, FooEnum>) conversionService.convert(foo, TypeDescriptor
|
||||
.valueOf(Map.class), new TypeDescriptor(getClass().getField("genericMap")));
|
||||
assertEquals(map.get(1), FooEnum.BAR);
|
||||
assertEquals(map.get(2), FooEnum.BAZ);
|
||||
assertEquals(FooEnum.BAR, map.get(1));
|
||||
assertEquals(FooEnum.BAZ, map.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -346,7 +347,8 @@ public class GenericConversionServiceTests {
|
|||
@Test
|
||||
public void convertStringToCollectionWithElementConversion() throws Exception {
|
||||
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(new Integer(1), result.get(0));
|
||||
assertEquals(new Integer(2), result.get(1));
|
||||
|
|
@ -391,6 +393,42 @@ public class GenericConversionServiceTests {
|
|||
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
|
||||
public void genericConverterDelegatingBackToConversionServiceConverterNotFound() {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue