Browse Source

polish

conversation
Keith Donald 16 years ago
parent
commit
ce8718ebf2
  1. 8
      org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
  2. 4
      org.springframework.core/src/main/java/org/springframework/core/convert/service/ArrayToCollection.java
  3. 3
      org.springframework.core/src/main/java/org/springframework/core/convert/service/CollectionToCollection.java
  4. 8
      org.springframework.core/src/main/java/org/springframework/core/convert/service/GenericConversionService.java
  5. 76
      org.springframework.core/src/main/java/org/springframework/core/convert/service/MapToMap.java
  6. 138
      org.springframework.core/src/test/java/org/springframework/core/convert/service/GenericConversionServiceTests.java

8
org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

@ -19,6 +19,7 @@ import java.lang.annotation.Annotation; @@ -19,6 +19,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
@ -135,6 +136,13 @@ public class TypeDescriptor { @@ -135,6 +136,13 @@ public class TypeDescriptor {
return Collection.class.isAssignableFrom(getType());
}
/**
* Is this type a {@link Map} type?
*/
public boolean isMap() {
return Map.class.isAssignableFrom(getType());
}
/**
* If this type is an array type or {@link Collection} type, returns the underlying element type.
* Returns null if the type is neither an array or collection.

4
org.springframework.core/src/main/java/org/springframework/core/convert/service/ArrayToCollection.java

@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
package org.springframework.core.convert.service;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Collection;
import org.springframework.core.convert.ConversionExecutor;
@ -47,8 +46,7 @@ class ArrayToCollection extends AbstractCollectionConverter { @@ -47,8 +46,7 @@ class ArrayToCollection extends AbstractCollectionConverter {
@SuppressWarnings("unchecked")
protected Object doExecute(Object sourceArray) throws Exception {
Class implClass = CollectionConversionUtils.getImpl(getTargetType().getType());
Constructor constructor = implClass.getConstructor((Class[]) null);
Collection collection = (Collection) constructor.newInstance((Object[]) null);
Collection collection = (Collection) implClass.newInstance();
int length = Array.getLength(sourceArray);
ConversionExecutor converter = getElementConverter();
for (int i = 0; i < length; i++) {

3
org.springframework.core/src/main/java/org/springframework/core/convert/service/CollectionToCollection.java

@ -40,8 +40,7 @@ class CollectionToCollection extends AbstractCollectionConverter { @@ -40,8 +40,7 @@ class CollectionToCollection extends AbstractCollectionConverter {
Collection sourceCollection = (Collection) source;
Class targetCollectionType = getTargetType().getType();
Class implClass = CollectionConversionUtils.getImpl(targetCollectionType);
Collection targetCollection = (Collection) implClass.getConstructor((Class[]) null)
.newInstance((Object[]) null);
Collection targetCollection = (Collection) implClass.newInstance();
ConversionExecutor elementConverter = getElementConverter();
Class elementType;
if (elementConverter == null) {

8
org.springframework.core/src/main/java/org/springframework/core/convert/service/GenericConversionService.java

@ -178,7 +178,6 @@ public class GenericConversionService implements ConversionService { @@ -178,7 +178,6 @@ public class GenericConversionService implements ConversionService {
throws ConversionExecutorNotFoundException {
Assert.notNull(sourceClass, "The sourceType to convert from is required");
Assert.notNull(targetType, "The targetType to convert to is required");
// special handling for arrays since they are not indexable classes
TypeDescriptor sourceType = TypeDescriptor.valueOf(sourceClass);
if (sourceType.isArray()) {
if (targetType.isArray()) {
@ -206,6 +205,13 @@ public class GenericConversionService implements ConversionService { @@ -206,6 +205,13 @@ public class GenericConversionService implements ConversionService {
throw new UnsupportedOperationException("Object to Collection conversion not yet supported");
}
}
if (sourceType.isMap()) {
if (targetType.isMap()) {
return new MapToMap(sourceType, targetType, this);
} else {
throw new UnsupportedOperationException("Object to Map conversion not yet supported");
}
}
Converter converter = findRegisteredConverter(sourceType, targetType);
if (converter != null) {
return new StaticConversionExecutor(sourceType, targetType, converter);

76
org.springframework.core/src/main/java/org/springframework/core/convert/service/MapToMap.java

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
/*
* Copyright 2004-2008 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.service;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.springframework.core.convert.ConversionExecutionException;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.TypeDescriptor;
class MapToMap implements ConversionExecutor {
private TypeDescriptor sourceType;
private TypeDescriptor targetType;
private GenericConversionService conversionService;
public MapToMap(TypeDescriptor sourceType, TypeDescriptor targetType, GenericConversionService conversionService) {
this.sourceType = sourceType;
this.targetType = targetType;
this.conversionService = conversionService;
}
@SuppressWarnings("unchecked")
public Object execute(Object source) throws ConversionExecutionException {
try {
Map map = (Map) source;
Map targetMap = (Map) getImpl(targetType.getType()).newInstance();
Iterator<Map.Entry<?, ?>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
Object key = entry.getKey();
Object value = entry.getValue();
key = conversionService.executeConversion(key, TypeDescriptor.valueOf(targetType.getMapKeyType()));
value = conversionService.executeConversion(value, TypeDescriptor.valueOf(targetType.getMapValueType()));
targetMap.put(key, value);
}
return targetMap;
} catch (Exception e) {
throw new ConversionExecutionException(source, sourceType, targetType, e);
}
}
static Class<?> getImpl(Class<?> targetClass) {
if (targetClass.isInterface()) {
if (Map.class.equals(targetClass)) {
return HashMap.class;
} else if (SortedMap.class.equals(targetClass)) {
return TreeMap.class;
} else {
throw new IllegalArgumentException("Unsupported Map interface [" + targetClass.getName() + "]");
}
} else {
return targetClass;
}
}
}

138
org.springframework.core/src/test/java/org/springframework/core/convert/service/GenericConversionServiceTests.java

@ -15,14 +15,19 @@ @@ -15,14 +15,19 @@
*/
package org.springframework.core.convert.service;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.fail;
import java.security.Principal;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import junit.framework.TestCase;
import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
@ -36,34 +41,39 @@ import org.springframework.core.convert.converter.NumberToNumber; @@ -36,34 +41,39 @@ import org.springframework.core.convert.converter.NumberToNumber;
import org.springframework.core.convert.converter.StringToEnum;
import org.springframework.core.convert.converter.StringToInteger;
public class GenericConversionServiceTests extends TestCase {
public class GenericConversionServiceTests {
private GenericConversionService service = new GenericConversionService();
public void testExecuteConversion() {
@Test
public void executeConversion() {
service.addConverter(new StringToInteger());
assertEquals(new Integer(3), service.executeConversion("3", type(Integer.class)));
}
public void testExecuteConversionNullSource() {
@Test
public void executeConversionNullSource() {
assertEquals(null, service.executeConversion(null, type(Integer.class)));
}
public void testConverterConversionForwardIndex() {
@Test
public void converterConvertForwardIndex() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(Integer.class));
Integer three = (Integer) executor.execute("3");
assertEquals(3, three.intValue());
}
public void testConverterConversionReverseIndex() {
@Test
public void convertReverseIndex() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(Integer.class, type(String.class));
String threeString = (String) executor.execute(new Integer(3));
assertEquals("3", threeString);
}
public void testConversionExecutorNotFound() {
@Test
public void convertExecutorNotFound() {
try {
service.getConversionExecutor(String.class, type(Integer.class));
fail("Should have thrown an exception");
@ -71,7 +81,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -71,7 +81,8 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testAddConverterNoSourceTargetClassInfoAvailable() {
@Test
public void addConverterNoSourceTargetClassInfoAvailable() {
try {
service.addConverter(new Converter() {
public Object convert(Object source) throws Exception {
@ -88,18 +99,21 @@ public class GenericConversionServiceTests extends TestCase { @@ -88,18 +99,21 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testConversionCompatibleTypes() {
@Test
public void convertCompatibleTypes() {
String source = "foo";
assertSame(source, service.getConversionExecutor(String.class, type(String.class)).execute(source));
}
public void testConversionExecutorNullArgument() {
@Test
public void convertNull() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(Integer.class));
assertNull(executor.execute(null));
}
public void testConversionExecutorWrongTypeArgument() {
@Test
public void convertWrongTypeArgument() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(Integer.class, type(String.class));
try {
@ -110,7 +124,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -110,7 +124,8 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testConverterConversionSuperSourceType() {
@Test
public void convertSuperSourceType() {
service.addConverter(new Converter<CharSequence, Integer>() {
public Integer convert(CharSequence source) throws Exception {
return Integer.valueOf(source.toString());
@ -125,7 +140,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -125,7 +140,8 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals(new Integer(3), result);
}
public void testConverterConversionNoSuperTargetType() {
@Test
public void convertNoSuperTargetType() {
service.addConverter(new Converter<CharSequence, Number>() {
public Integer convert(CharSequence source) throws Exception {
return Integer.valueOf(source.toString());
@ -143,14 +159,16 @@ public class GenericConversionServiceTests extends TestCase { @@ -143,14 +159,16 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testConversionObjectToPrimitive() {
@Test
public void convertObjectToPrimitive() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(int.class));
Integer three = (Integer) executor.execute("3");
assertEquals(3, three.intValue());
}
public void testConversionArrayToArray() {
@Test
public void convertArrayToArray() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String[].class, type(Integer[].class));
Integer[] result = (Integer[]) executor.execute(new String[] { "1", "2", "3" });
@ -159,7 +177,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -159,7 +177,8 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals(new Integer(3), result[2]);
}
public void testConversionArrayToPrimitiveArray() {
@Test
public void convertArrayToPrimitiveArray() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String[].class, type(int[].class));
int[] result = (int[]) executor.execute(new String[] { "1", "2", "3" });
@ -168,7 +187,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -168,7 +187,8 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals(3, result[2]);
}
public void testConversionArrayToListInterface() {
@Test
public void convertArrayToListInterface() {
ConversionExecutor executor = service.getConversionExecutor(String[].class, type(List.class));
List result = (List) executor.execute(new String[] { "1", "2", "3" });
assertEquals("1", result.get(0));
@ -177,17 +197,20 @@ public class GenericConversionServiceTests extends TestCase { @@ -177,17 +197,20 @@ public class GenericConversionServiceTests extends TestCase {
}
public List<Integer> genericList = new ArrayList<Integer>();
public void testConversionArrayToListGenericTypeConversion() throws Exception {
@Test
public void convertArrayToListGenericTypeConversion() throws Exception {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String[].class, new TypeDescriptor(getClass().getDeclaredField("genericList")));
ConversionExecutor executor = service.getConversionExecutor(String[].class, new TypeDescriptor(getClass()
.getDeclaredField("genericList")));
List result = (List) executor.execute(new String[] { "1", "2", "3" });
assertEquals(new Integer("1"), result.get(0));
assertEquals(new Integer("2"), result.get(1));
assertEquals(new Integer("3"), result.get(2));
}
public void testConversionArrayToListImpl() {
@Test
public void convertArrayToListImpl() {
ConversionExecutor executor = service.getConversionExecutor(String[].class, type(LinkedList.class));
LinkedList result = (LinkedList) executor.execute(new String[] { "1", "2", "3" });
assertEquals("1", result.get(0));
@ -195,7 +218,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -195,7 +218,8 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals("3", result.get(2));
}
public void testConversionArrayToAbstractList() {
@Test
public void convertArrayToAbstractList() {
try {
service.getConversionExecutor(String[].class, type(AbstractList.class));
} catch (IllegalArgumentException e) {
@ -203,7 +227,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -203,7 +227,8 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testConversionListToArray() {
@Test
public void convertListToArray() {
ConversionExecutor executor = service.getConversionExecutor(Collection.class, type(String[].class));
List list = new ArrayList();
list.add("1");
@ -215,7 +240,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -215,7 +240,8 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals("3", result[2]);
}
public void testConversionListToArrayWithComponentConversion() {
@Test
public void convertListToArrayWithComponentConversion() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(Collection.class, type(Integer[].class));
List list = new ArrayList();
@ -228,9 +254,21 @@ public class GenericConversionServiceTests extends TestCase { @@ -228,9 +254,21 @@ public class GenericConversionServiceTests extends TestCase {
assertEquals(new Integer(3), result[2]);
}
public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>();
@Test
public void convertMapToMap() throws Exception {
Map<String, String> foo = new HashMap<String, String>();
foo.put("1", "BAR");
foo.put("2", "BAZ");
service.addConverter(new StringToInteger());
service.addConverter(new StringToEnum());
service.executeConversion(foo, new TypeDescriptor(getClass().getField("genericMap")));
}
@Ignore
@Test
public void conversionObjectToArray() {
public void convertObjectToArray() {
ConversionExecutor executor = service.getConversionExecutor(String.class, type(String[].class));
String[] result = (String[]) executor.execute("1,2,3");
assertEquals(1, result.length);
@ -238,8 +276,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -238,8 +276,8 @@ public class GenericConversionServiceTests extends TestCase {
}
@Ignore
@Test
public void conversionObjectToArrayWithElementConversion() {
@Test
public void convertObjectToArrayWithElementConversion() {
service.addConverter(new StringToInteger());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(Integer[].class));
Integer[] result = (Integer[]) executor.execute("123");
@ -248,22 +286,25 @@ public class GenericConversionServiceTests extends TestCase { @@ -248,22 +286,25 @@ public class GenericConversionServiceTests extends TestCase {
}
public static enum FooEnum {
BAR
BAR, BAZ
}
public void testSuperConverterConversionForwardIndex() {
@Test
public void superConverterConvertForwardIndex() {
service.addConverter(new StringToEnum());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(FooEnum.class));
assertEquals(FooEnum.BAR, executor.execute("BAR"));
}
public void testSuperTwoWayConverterConversionReverseIndex() {
@Test
public void superTwoWayConverterConvertReverseIndex() {
service.addConverter(new StringToEnum());
ConversionExecutor executor = service.getConversionExecutor(FooEnum.class, type(String.class));
assertEquals("BAR", executor.execute(FooEnum.BAR));
}
public void testSuperConverterConversionNotConvertibleAbstractType() {
@Test
public void superConverterConvertNotConvertibleAbstractType() {
service.addConverter(new StringToEnum());
ConversionExecutor executor = service.getConversionExecutor(String.class, type(Enum.class));
try {
@ -274,7 +315,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -274,7 +315,8 @@ public class GenericConversionServiceTests extends TestCase {
}
}
public void testSuperConverterConversionNotConvertibleAbstractType2() {
@Test
public void superConverterConvertNotConvertibleAbstractType2() {
service.addConverter(new NumberToNumber());
Number customNumber = new Number() {
@Override
@ -308,7 +350,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -308,7 +350,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionForwardIndex() {
public void customConverterConvertForwardIndex() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", String.class, type(Principal.class));
assertEquals("keith", ((Principal) executor.execute("keith")).getName());
@ -316,7 +358,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -316,7 +358,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionReverseIndex() {
public void customConverterConvertReverseIndex() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", Principal.class, type(String.class));
assertEquals("keith", executor.execute(new Principal() {
@ -328,7 +370,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -328,7 +370,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionForSameType() {
public void customConverterConvertForSameType() {
service.addConverter("trimmer", new Trimmer());
ConversionExecutor executor = service.getConversionExecutor("trimmer", String.class, type(String.class));
assertEquals("a string", executor.execute("a string "));
@ -370,7 +412,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -370,7 +412,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionArrayToArray() {
public void customConverterConvertArrayToArray() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", String[].class, type(Principal[].class));
Principal[] p = (Principal[]) executor.execute(new String[] { "princy1", "princy2" });
@ -380,7 +422,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -380,7 +422,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionArrayToArrayReverse() {
public void customConverterConvertArrayToArrayReverse() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", Principal[].class, type(String[].class));
final Principal princy1 = new Principal() {
@ -422,7 +464,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -422,7 +464,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionArrayToCollection() {
public void customConverterConvertArrayToCollection() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", String[].class, type(List.class));
List list = (List) executor.execute(new String[] { "princy1", "princy2" });
@ -432,7 +474,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -432,7 +474,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionArrayToCollectionReverse() {
public void customConverterConvertArrayToCollectionReverse() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", Principal[].class, type(List.class));
final Principal princy1 = new Principal() {
@ -512,7 +554,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -512,7 +554,7 @@ public class GenericConversionServiceTests extends TestCase {
@Ignore
@Test
public void customConverterConversionObjectToArray() {
public void customConverterConvertObjectToArray() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", String.class, type(Principal[].class));
Principal[] p = (Principal[]) executor.execute("princy1");
@ -520,8 +562,8 @@ public class GenericConversionServiceTests extends TestCase { @@ -520,8 +562,8 @@ public class GenericConversionServiceTests extends TestCase {
}
@Ignore
@Test
public void customConverterConversionObjectToArrayReverse() {
@Test
public void customConverterConvertObjectToArrayReverse() {
service.addConverter("princy", new CustomTwoWayConverter());
ConversionExecutor executor = service.getConversionExecutor("princy", Principal.class, type(String[].class));
final Principal princy1 = new Principal() {
@ -534,7 +576,7 @@ public class GenericConversionServiceTests extends TestCase { @@ -534,7 +576,7 @@ public class GenericConversionServiceTests extends TestCase {
}
@Ignore
@Test
@Test
public void customConverterLookupObjectToArrayBogusSource() {
service.addConverter("princy", new CustomTwoWayConverter());
try {
@ -577,9 +619,9 @@ public class GenericConversionServiceTests extends TestCase { @@ -577,9 +619,9 @@ public class GenericConversionServiceTests extends TestCase {
service.addConverter(GenericConversionService.converterFor(String.class, FooEnum.class, new StringToEnum()));
assertEquals(FooEnum.BAR, service.executeConversion("BAR", type(FooEnum.class)));
}
private TypeDescriptor type(Class<?> clazz) {
return TypeDescriptor.valueOf(clazz);
}
}
Loading…
Cancel
Save