/*
* Copyright 2002-2014 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.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import junit.framework.TestCase;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import android.graphics.Color;
import android.os.Build;
/**
* @author Keith Donald
* @author Juergen Hoeller
* @author Phillip Webb
*/
public class GenericConversionServiceTests extends TestCase {
private GenericConversionService conversionService = new GenericConversionService();
public void testCanConvert() {
assertFalse(conversionService.canConvert(String.class, Integer.class));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(String.class, Integer.class));
}
public void testCanConvertAssignable() {
assertTrue(conversionService.canConvert(String.class, String.class));
assertTrue(conversionService.canConvert(Integer.class, Number.class));
assertTrue(conversionService.canConvert(boolean.class, boolean.class));
assertTrue(conversionService.canConvert(boolean.class, Boolean.class));
}
public void testCanConvertIllegalArgumentNullTargetType() {
try {
assertFalse(conversionService.canConvert(String.class, null));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
}
try {
assertFalse(conversionService.canConvert(TypeDescriptor.valueOf(String.class), null));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
}
}
public void testCanConvertNullSourceType() {
assertTrue(conversionService.canConvert(null, Integer.class));
assertTrue(conversionService.canConvert(null, TypeDescriptor.valueOf(Integer.class)));
}
public void testConvert() {
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertEquals(new Integer(3), conversionService.convert("3", Integer.class));
}
public void testConvertNullSource() {
assertEquals(null, conversionService.convert(null, Integer.class));
}
public void testConvertNullSourcePrimitiveTarget() {
try {
assertEquals(null, conversionService.convert(null, int.class));
fail("expected ConversionFailedException");
}
catch (ConversionFailedException e) {
}
}
public void testConvertNullSourcePrimitiveTargetTypeDescriptor() {
try {
conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(int.class));
fail("expected ConversionFailedException");
}
catch (ConversionFailedException e) {
}
}
public void testConvertNotNullSourceNullSourceTypeDescriptor() {
try {
conversionService.convert("3", null, TypeDescriptor.valueOf(int.class));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
}
}
public void testConvertAssignableSource() {
assertEquals(Boolean.FALSE, conversionService.convert(false, boolean.class));
assertEquals(Boolean.FALSE, conversionService.convert(false, Boolean.class));
}
public void testConverterNotFound() {
try {
conversionService.convert("3", Integer.class);
fail("expected ConverterNotFoundException");
}
catch (ConverterNotFoundException e) {
}
}
@SuppressWarnings("rawtypes")
public void testAddConverterNoSourceTargetClassInfoAvailable() {
try {
conversionService.addConverter(new Converter() {
@Override
public Object convert(Object source) {
return source;
}
});
fail("Should have failed");
}
catch (IllegalArgumentException ex) {
}
}
public void testSourceTypeIsVoid() {
GenericConversionService conversionService = new GenericConversionService();
assertFalse(conversionService.canConvert(void.class, String.class));
}
public void testTargetTypeIsVoid() {
GenericConversionService conversionService = new GenericConversionService();
assertFalse(conversionService.canConvert(String.class, void.class));
}
public void testConvertNull() {
assertNull(conversionService.convert(null, Integer.class));
}
public void testConvertNullTargetClass() {
try {
assertNull(conversionService.convert("3", (Class<?>) null));
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
}
}
public void testConvertNullTypeDescriptor() {
try {
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
}
}
public void testConvertWrongSourceTypeDescriptor() {
try {
conversionService.convert("3", TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Long.class));
fail("expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
}
}
public void testConvertWrongTypeArgument() {
conversionService.addConverterFactory(new StringToNumberConverterFactory());
try {
conversionService.convert("BOGUS", Integer.class);
fail("expected ConversionFailedException");
}
catch (ConversionFailedException e) {
}
}
public void testConvertSuperSourceType() {
conversionService.addConverter(new Converter<CharSequence, Integer>() {
@Override
public Integer convert(CharSequence source) {
return Integer.valueOf(source.toString());
}
});
Integer result = conversionService.convert("3", Integer.class);
assertEquals(new Integer(3), result);
}
// SPR-8718
// @Test(expected=ConverterNotFoundException.class)
// public void convertSuperTarget() {
// conversionService.addConverter(new ColorConverter());
// conversionService.convert("#000000", SystemColor.class);
// }
//
// public class ColorConverter implements Converter<String, Color> {
// @Override
// public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); }
// }
public void testConvertObjectToPrimitive() {
assertFalse(conversionService.canConvert(String.class, boolean.class));
conversionService.addConverter(new StringToBooleanConverter());
assertTrue(conversionService.canConvert(String.class, boolean.class));
Boolean b = conversionService.convert("true", boolean.class);
assertEquals(Boolean.TRUE, b);
assertTrue(conversionService.canConvert(TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(boolean.class)));
b = (Boolean) conversionService.convert("true", TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(boolean.class));
assertEquals(Boolean.TRUE, b);
}
public void testConvertObjectToPrimitiveViaConverterFactory() {
assertFalse(conversionService.canConvert(String.class, int.class));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(String.class, int.class));
Integer three = conversionService.convert("3", int.class);
assertEquals(3, three.intValue());
}
public void testGenericConverterDelegatingBackToConversionServiceConverterNotFound() {
conversionService.addConverter(new ObjectToArrayConverter(conversionService));
assertFalse(conversionService.canConvert(String.class, Integer[].class));
try {
conversionService.convert("3,4,5", Integer[].class);
fail("expected ConverterNotFoundException");
}
catch (ConverterNotFoundException ex) {
}
}
public void testListToIterableConversion() {
GenericConversionService conversionService = new GenericConversionService();
List<Object> raw = new ArrayList<Object>();
raw.add("one");
raw.add("two");
Object converted = conversionService.convert(raw, Iterable.class);
assertSame(raw, converted);
}
public void testListToObjectConversion() {
GenericConversionService conversionService = new GenericConversionService();
List<Object> raw = new ArrayList<Object>();
raw.add("one");
raw.add("two");
Object converted = conversionService.convert(raw, Object.class);
assertSame(raw, converted);
}
public void testMapToObjectConversion() {
GenericConversionService conversionService = new GenericConversionService();
Map<Object, Object> raw = new HashMap<Object, Object>();
raw.put("key", "value");
Object converted = conversionService.convert(raw, Object.class);
assertSame(raw, converted);
}
public void testInterfaceToString() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new ObjectToStringConverter());
Object converted = conversionService.convert(new MyInterfaceImplementer(), String.class);
assertEquals("RESULT", converted);
}
public void testInterfaceArrayToStringArray() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new ArrayToArrayConverter(conversionService));
String[] converted = conversionService.convert(new MyInterface[] {new MyInterfaceImplementer()}, String[].class);
assertEquals("RESULT", converted[0]);
}
public void testObjectArrayToStringArray() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new ArrayToArrayConverter(conversionService));
String[] converted = conversionService.convert(new MyInterfaceImplementer[] {new MyInterfaceImplementer()}, String[].class);
assertEquals("RESULT", converted[0]);
}
public void testStringArrayToResourceArray() {
GenericConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new MyStringArrayToResourceArrayConverter());
Resource[] converted = conversionService.convert(new String[] {"x1", "z3"}, Resource[].class);
assertEquals(2, converted.length);
assertEquals("1", converted[0].getDescription());
assertEquals("3", converted[1].getDescription());
}
public void testStringArrayToIntegerArray() {
GenericConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new MyStringArrayToIntegerArrayConverter());
Integer[] converted = conversionService.convert(new String[] {"x1", "z3"}, Integer[].class);
assertEquals(2, converted.length);
assertEquals(1, converted[0].intValue());
assertEquals(3, converted[1].intValue());
}
public void testStringToIntegerArray() {
GenericConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new MyStringToIntegerArrayConverter());
Integer[] converted = conversionService.convert("x1,z3", Integer[].class);
assertEquals(2, converted.length);
assertEquals(1, converted[0].intValue());
assertEquals(3, converted[1].intValue());
}
public void testWildcardMap() throws Exception {
GenericConversionService conversionService = new DefaultConversionService();
Map<String, String> input = new LinkedHashMap<String, String>();
input.put("key", "value");
Object converted = conversionService.convert(input, TypeDescriptor.forObject(input), new TypeDescriptor(getClass().getField("wildcardMap")));
assertEquals(input, converted);
}
public void testListOfList() {
GenericConversionService service = new DefaultConversionService();
List<String> list1 = Arrays.asList("Foo", "Bar");
List<String> list2 = Arrays.asList("Baz", "Boop");
List<List<String>> list = Arrays.asList(list1, list2);
String result = service.convert(list, String.class);
assertNotNull(result);
assertEquals("Foo,Bar,Baz,Boop", result);
}
public void testStringToString() {
GenericConversionService service = new DefaultConversionService();
String value = "myValue";
String result = service.convert(value, String.class);
assertSame(value, result);
}
public void testStringToObject() {
GenericConversionService service = new DefaultConversionService();
String value = "myValue";
Object result = service.convert(value, Object.class);
assertSame(value, result);
}
public void testIgnoreCopyConstructor() {
GenericConversionService service = new DefaultConversionService();
WithCopyConstructor value = new WithCopyConstructor();
Object result = service.convert(value, WithCopyConstructor.class);
assertSame(value, result);
}
public void testConvertUUID() {
GenericConversionService service = new DefaultConversionService();
UUID uuid = UUID.randomUUID();
String convertToString = service.convert(uuid, String.class);
UUID convertToUUID = service.convert(convertToString, UUID.class);
assertEquals(uuid, convertToUUID);
}
// public void testPerformance1() {
// Assume.group(TestGroup.PERFORMANCE);
// GenericConversionService conversionService = new DefaultConversionService();
// StopWatch watch = new StopWatch("integer->string conversionPerformance");
// watch.start("convert 4,000,000 with conversion service");
// for (int i = 0; i < 4000000; i++) {
// conversionService.convert(3, String.class);
// }
// watch.stop();
// watch.start("convert 4,000,000 manually");
// for (int i = 0; i < 4000000; i++) {
// new Integer(3).toString();
// }
// watch.stop();
// System.out.println(watch.prettyPrint());
// }
// public void testPerformance2() throws Exception {
// Assume.group(TestGroup.PERFORMANCE);
// GenericConversionService conversionService = new DefaultConversionService();
// StopWatch watch = new StopWatch("list<string> -> list<integer> conversionPerformance");
// watch.start("convert 4,000,000 with conversion service");
// List<String> source = new LinkedList<String>();
// source.add("1");
// source.add("2");
// source.add("3");
// TypeDescriptor td = new TypeDescriptor(getClass().getField("list"));
// for (int i = 0; i < 1000000; i++) {
// conversionService.convert(source, TypeDescriptor.forObject(source), td);
// }
// watch.stop();
// watch.start("convert 4,000,000 manually");
// for (int i = 0; i < 4000000; i++) {
// List<Integer> target = new ArrayList<Integer>(source.size());
// for (String element : source) {
// target.add(Integer.valueOf(element));
// }
// }
// watch.stop();
// System.out.println(watch.prettyPrint());
// }
public static List<Integer> list;
// public void testPerformance3() throws Exception {
// Assume.group(TestGroup.PERFORMANCE);
// GenericConversionService conversionService = new DefaultConversionService();
// StopWatch watch = new StopWatch("map<string, string> -> map<string, integer> conversionPerformance");
// watch.start("convert 4,000,000 with conversion service");
// Map<String, String> source = new HashMap<String, String>();
// source.put("1", "1");
// source.put("2", "2");
// source.put("3", "3");
// TypeDescriptor td = new TypeDescriptor(getClass().getField("map"));
// for (int i = 0; i < 1000000; i++) {
// conversionService.convert(source, TypeDescriptor.forObject(source), td);
// }
// watch.stop();
// watch.start("convert 4,000,000 manually");
// for (int i = 0; i < 4000000; i++) {
// Map<String, Integer> target = new HashMap<String, Integer>(source.size());
// for (Map.Entry<String, String> entry : source.entrySet()) {
// target.put(entry.getKey(), Integer.valueOf(entry.getValue()));
// }
// }
// watch.stop();
// System.out.println(watch.prettyPrint());
// }
public static Map<String, Integer> map;
public void testEmptyListToArray() {
conversionService.addConverter(new CollectionToArrayConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
List<String> list = new ArrayList<String>();
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = TypeDescriptor.valueOf(String[].class);
assertTrue(conversionService.canConvert(sourceType, targetType));
assertEquals(0, ((String[])conversionService.convert(list, sourceType, targetType)).length);
}
public void testEmptyListToObject() {
conversionService.addConverter(new CollectionToObjectConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
List<String> list = new ArrayList<String>();
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = TypeDescriptor.valueOf(Integer.class);
assertTrue(conversionService.canConvert(sourceType, targetType));
assertNull(conversionService.convert(list, sourceType, targetType));
}
private interface MyBaseInterface {
}
private interface MyInterface extends MyBaseInterface {
}
private static class MyInterfaceImplementer implements MyInterface {
}
private static class MyBaseInterfaceConverter implements Converter<MyBaseInterface, String> {
@Override
public String convert(MyBaseInterface source) {
return "RESULT";
}
}
private static class MyStringArrayToResourceArrayConverter implements Converter<String[], Resource[]> {
@Override
public Resource[] convert(String[] source) {
Resource[] result = new Resource[source.length];
for (int i = 0; i < source.length; i++) {
result[i] = new DescriptiveResource(source[i].substring(1));
}
return result;
}
}
private static class MyStringArrayToIntegerArrayConverter implements Converter<String[], Integer[]> {
@Override
public Integer[] convert(String[] source) {
Integer[] result = new Integer[source.length];
for (int i = 0; i < source.length; i++) {
result[i] = Integer.parseInt(source[i].substring(1));
}
return result;
}
}
private static class MyStringToIntegerArrayConverter implements Converter<String, Integer[]> {
@Override
public Integer[] convert(String source) {
String[] srcArray = StringUtils.commaDelimitedListToStringArray(source);
Integer[] result = new Integer[srcArray.length];
for (int i = 0; i < srcArray.length; i++) {
result[i] = Integer.parseInt(srcArray[i].substring(1));
}
return result;
}
}
public static class WithCopyConstructor {
public WithCopyConstructor() {
}
public WithCopyConstructor(WithCopyConstructor value) {
}
}
public static Map<String, ?> wildcardMap;
public void testStringToArrayCanConvert() {
conversionService.addConverter(new StringToArrayConverter(conversionService));
assertFalse(conversionService.canConvert(String.class, Integer[].class));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(String.class, Integer[].class));
}
public void testStringToCollectionCanConvert() throws Exception {
conversionService.addConverter(new StringToCollectionConverter(conversionService));
assertTrue(conversionService.canConvert(String.class, Collection.class));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("stringToCollection"));
assertFalse(conversionService.canConvert(TypeDescriptor.valueOf(String.class), targetType));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(TypeDescriptor.valueOf(String.class), targetType));
}
public Collection<Integer> stringToCollection;
public void testConvertiblePairsInSet() {
Set<GenericConverter.ConvertiblePair> set = new HashSet<GenericConverter.ConvertiblePair>();
set.add(new GenericConverter.ConvertiblePair(Number.class, String.class));
assert set.contains(new GenericConverter.ConvertiblePair(Number.class, String.class));
}
public void testConvertiblePairEqualsAndHash() {
GenericConverter.ConvertiblePair pair = new GenericConverter.ConvertiblePair(Number.class, String.class);
GenericConverter.ConvertiblePair pairEqual = new GenericConverter.ConvertiblePair(Number.class, String.class);
assertEquals(pair, pairEqual);
assertEquals(pair.hashCode(), pairEqual.hashCode());
}
public void testConvertiblePairDifferentEqualsAndHash() {
GenericConverter.ConvertiblePair pair = new GenericConverter.ConvertiblePair(Number.class, String.class);
GenericConverter.ConvertiblePair pairOpposite = new GenericConverter.ConvertiblePair(String.class, Number.class);
assertFalse(pair.equals(pairOpposite));
assertFalse(pair.hashCode() == pairOpposite.hashCode());
}
public void testConvertPrimitiveArray() {
GenericConversionService conversionService = new DefaultConversionService();
byte[] byteArray = new byte[] { 1, 2, 3 };
Byte[] converted = conversionService.convert(byteArray, Byte[].class);
assertTrue(Arrays.equals(converted, new Byte[] {1, 2, 3}));
}
public void testCanConvertIllegalArgumentNullTargetTypeFromClass() {
try {
conversionService.canConvert(String.class, null);
fail("Did not thow IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
}
}
public void testCanConvertIllegalArgumentNullTargetTypeFromTypeDescriptor() {
try {
conversionService.canConvert(TypeDescriptor.valueOf(String.class), null);
fail("Did not thow IllegalArgumentException");
}
catch(IllegalArgumentException ex) {
}
}
@SuppressWarnings({ "rawtypes" })
public void testConvertHashMapValuesToList() {
GenericConversionService conversionService = new DefaultConversionService();
Map<String, Integer> hashMap = new LinkedHashMap<String, Integer>();
hashMap.put("1", 1);
hashMap.put("2", 2);
List converted = conversionService.convert(hashMap.values(), List.class);
assertEquals(Arrays.asList(1, 2), converted);
}
// public void testRemoveConvertible() {
// conversionService.addConverter(new ColorConverter());
// assertTrue(conversionService.canConvert(String.class, Color.class));
// conversionService.removeConvertible(String.class, Color.class);
// assertFalse(conversionService.canConvert(String.class, Color.class));
// }
// public void testConditionalConverter() {
// GenericConversionService conversionService = new GenericConversionService();
// MyConditionalConverter converter = new MyConditionalConverter();
// conversionService.addConverter(new ColorConverter());
// conversionService.addConverter(converter);
// assertEquals(Color.BLACK, conversionService.convert("#000000", Color.class));
// assertTrue(converter.getMatchAttempts() > 0);
// }
// public void testConditionalConverterFactory() {
// GenericConversionService conversionService = new GenericConversionService();
// MyConditionalConverterFactory converter = new MyConditionalConverterFactory();
// conversionService.addConverter(new ColorConverter());
// conversionService.addConverterFactory(converter);
// assertEquals(Color.BLACK, conversionService.convert("#000000", Color.class));
// assertTrue(converter.getMatchAttempts() > 0);
// assertTrue(converter.getNestedMatchAttempts() > 0);
// }
public void testShouldNotSupportNullConvertibleTypesFromNonConditionalGenericConverter() {
GenericConversionService conversionService = new GenericConversionService();
GenericConverter converter = new GenericConverter() {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return null;
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return null;
}
};
try {
conversionService.addConverter(converter);
fail("Did not throw");
}
catch (IllegalStateException ex) {
assertEquals("Only conditional converters may return null convertible types", ex.getMessage());
}
}
public void testConditionalConversionForAllTypes() {
GenericConversionService conversionService = new GenericConversionService();
MyConditionalGenericConverter converter = new MyConditionalGenericConverter();
conversionService.addConverter(converter);
assertEquals((Integer) 3, conversionService.convert(3, Integer.class));
// assertThat(converter.getSourceTypes().size(), greaterThan(2));
Iterator<TypeDescriptor> iterator = converter.getSourceTypes().iterator();
while(iterator.hasNext()) {
assertEquals(Integer.class, iterator.next().getType());
}
}
public void testConvertOptimizeArray() {
// SPR-9566
GenericConversionService conversionService = new DefaultConversionService();
byte[] byteArray = new byte[] { 1, 2, 3 };
byte[] converted = conversionService.convert(byteArray, byte[].class);
assertSame(byteArray, converted);
}
public void testConvertCannotOptimizeArray() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new Converter<Byte, Byte>() {
@Override
public Byte convert(Byte source) {
return (byte) (source + 1);
}
});
DefaultConversionService.addDefaultConverters(conversionService);
byte[] byteArray = new byte[] { 1, 2, 3 };
byte[] converted = conversionService.convert(byteArray, byte[].class);
assertNotSame(byteArray, converted);
assertTrue(Arrays.equals(new byte[] {2, 3, 4}, converted));
}
public void testEnumToStringConversion() {
conversionService.addConverter(new EnumToStringConverter(conversionService));
String result = conversionService.convert(MyEnum.A, String.class);
assertEquals("A", result);
}
public void testEnumWithInterfaceToStringConversion() {
// SPR-9692
// Android 2.2 has some issues with reflection
// see https://code.google.com/p/android/issues/detail?id=6636
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
conversionService.addConverter(new EnumToStringConverter(conversionService));
conversionService.addConverter(new MyEnumInterfaceToStringConverter<MyEnum>());
String result = conversionService.convert(MyEnum.A, String.class);
assertEquals("1", result);
}
}
public void testConvertNullAnnotatedStringToString() throws Exception {
DefaultConversionService.addDefaultConverters(conversionService);
String source = null;
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("annotatedString"));
TypeDescriptor targetType = TypeDescriptor.valueOf(String.class);
conversionService.convert(source, sourceType, targetType);
}
public void testMultipleCollectionTypesFromSameSourceType() throws Exception {
conversionService.addConverter(new MyStringToRawCollectionConverter());
conversionService.addConverter(new MyStringToGenericCollectionConverter());
conversionService.addConverter(new MyStringToStringCollectionConverter());
conversionService.addConverter(new MyStringToIntegerCollectionConverter());
assertEquals(Collections.singleton(4), // should be "testX" from MyStringToStringCollectionConverter, ideally
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
assertEquals(Collections.singleton(4), // should be "testX" from MyStringToStringCollectionConverter, ideally
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
}
public void testAdaptedCollectionTypesFromSameSourceType() throws Exception {
conversionService.addConverter(new MyStringToStringCollectionConverter());
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
// The following is unpleasant but simply a consequence of the raw type matching algorithm in Spring 3.x
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection"))));
}
public void testGenericCollectionAsSource() throws Exception {
conversionService.addConverter(new MyStringToGenericCollectionConverter());
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
// The following is unpleasant but a consequence of the generic collection converter above...
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection"))));
}
public void testRawCollectionAsSource() throws Exception {
conversionService.addConverter(new MyStringToRawCollectionConverter());
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
// The following is unpleasant but a consequence of the raw collection converter above...
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection"))));
}
@ExampleAnnotation
public String annotatedString;
@Retention(RetentionPolicy.RUNTIME)
public static @interface ExampleAnnotation {
}
private static class MyConditionalConverter implements Converter<String, Color>, ConditionalConverter {
private int matchAttempts = 0;
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
matchAttempts++;
return false;
}
@Override
public Color convert(String source) {
throw new IllegalStateException();
}
public int getMatchAttempts() {
return matchAttempts;
}
}
private static class MyConditionalGenericConverter implements GenericConverter, ConditionalConverter {
private List<TypeDescriptor> sourceTypes = new ArrayList<TypeDescriptor>();
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return null;
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
sourceTypes.add(sourceType);
return false;
}
@Override
public Object convert(Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
return null;
}
public List<TypeDescriptor> getSourceTypes() {
return sourceTypes;
}
}
private static class MyConditionalConverterFactory implements ConverterFactory<String, Color>, ConditionalConverter {
private MyConditionalConverter converter = new MyConditionalConverter();
private int matchAttempts = 0;
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
matchAttempts++;
return true;
}
@Override
@SuppressWarnings("unchecked")
public <T extends Color> Converter<String, T> getConverter(Class<T> targetType) {
return (Converter<String, T>) converter;
}
public int getMatchAttempts() {
return matchAttempts;
}
public int getNestedMatchAttempts() {
return converter.getMatchAttempts();
}
}
interface MyEnumInterface {
String getCode();
}
public static enum MyEnum implements MyEnumInterface {
A {
@Override
public String getCode() {
return "1";
}
}
}
public static class MyStringToRawCollectionConverter implements Converter<String, Collection> {
@Override
public Collection convert(String source) {
return Collections.singleton(source + "X");
}
}
public static class MyStringToGenericCollectionConverter implements Converter<String, Collection<?>> {
@Override
public Collection<?> convert(String source) {
return Collections.singleton(source + "X");
}
}
private static class MyEnumInterfaceToStringConverter<T extends MyEnumInterface> implements Converter<T, String> {
@Override
public String convert(T source) {
return source.getCode();
}
}
public static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> {
@Override
public Collection<String> convert(String source) {
return Collections.singleton(source + "X");
}
}
public static class MyStringToIntegerCollectionConverter implements Converter<String, Collection<Integer>> {
@Override
public Collection<Integer> convert(String source) {
return Collections.singleton(source.length());
}
}
public Collection rawCollection;
public Collection<?> genericCollection;
public Collection<String> stringCollection;
public Collection<Integer> integerCollection;
}