提交 387c8a81 编写于 作者: J Juergen Hoeller

Differentiate between TypeDescriptors with same annotations but different attributes

Issue: SPR-13714
上级 06056e6a
......@@ -468,7 +468,7 @@ public class TypeDescriptor implements Serializable {
return false;
}
for (Annotation ann : getAnnotations()) {
if (!other.hasAnnotation(ann.annotationType())) {
if (!ann.equals(other.getAnnotation(ann.annotationType()))) {
return false;
}
}
......
......@@ -478,6 +478,21 @@ public class GenericConversionServiceTests {
assertTrue(converter.getNestedMatchAttempts() > 0);
}
@Test
public void conditionalConverterCachingForDifferentAnnotationAttributes() throws Exception {
conversionService.addConverter(new ColorConverter());
conversionService.addConverter(new MyConditionalColorConverter());
assertEquals(Color.BLACK, conversionService.convert("000000xxxx",
new TypeDescriptor(getClass().getField("activeColor"))));
assertEquals(Color.BLACK, conversionService.convert(" #000000 ",
new TypeDescriptor(getClass().getField("inactiveColor"))));
assertEquals(Color.BLACK, conversionService.convert("000000yyyy",
new TypeDescriptor(getClass().getField("activeColor"))));
assertEquals(Color.BLACK, conversionService.convert(" #000000 ",
new TypeDescriptor(getClass().getField("inactiveColor"))));
}
@Test
public void shouldNotSupportNullConvertibleTypesFromNonConditionalGenericConverter() {
GenericConverter converter = new NonConditionalGenericConverter();
......@@ -629,14 +644,49 @@ public class GenericConversionServiceTests {
}
@ExampleAnnotation(active = true)
public String annotatedString;
@ExampleAnnotation(active = true)
public Color activeColor;
@ExampleAnnotation(active = false)
public Color inactiveColor;
public List<Integer> list;
public Map<String, Integer> map;
public Map<String, ?> wildcardMap;
@SuppressWarnings("rawtypes")
public Collection rawCollection;
public Collection<?> genericCollection;
public Collection<String> stringCollection;
public Collection<Integer> integerCollection;
@Retention(RetentionPolicy.RUNTIME)
private static @interface ExampleAnnotation {}
private @interface ExampleAnnotation {
boolean active();
}
private interface MyBaseInterface {
}
private static interface MyBaseInterface {}
private static interface MyInterface extends MyBaseInterface {}
private interface MyInterface extends MyBaseInterface {
}
private static class MyInterfaceImplementer implements MyInterface {
}
private static class MyInterfaceImplementer implements MyInterface {}
private static class MyBaseInterfaceToStringConverter implements Converter<MyBaseInterface, String> {
......@@ -646,6 +696,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringArrayToResourceArrayConverter implements Converter<String[], Resource[]> {
@Override
......@@ -654,6 +705,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringArrayToIntegerArrayConverter implements Converter<String[], Integer[]> {
@Override
......@@ -662,6 +714,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringToIntegerArrayConverter implements Converter<String, Integer[]> {
@Override
......@@ -671,6 +724,7 @@ public class GenericConversionServiceTests {
}
}
private static class WithCopyConstructor {
WithCopyConstructor() {}
......@@ -679,6 +733,7 @@ public class GenericConversionServiceTests {
WithCopyConstructor(WithCopyConstructor value) {}
}
private static class MyConditionalConverter implements Converter<String, Color>, ConditionalConverter {
private int matchAttempts = 0;
......@@ -699,6 +754,7 @@ public class GenericConversionServiceTests {
}
}
private static class NonConditionalGenericConverter implements GenericConverter {
@Override
......@@ -712,6 +768,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyConditionalGenericConverter implements GenericConverter, ConditionalConverter {
private final List<TypeDescriptor> sourceTypes = new ArrayList<TypeDescriptor>();
......@@ -737,6 +794,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyConditionalConverterFactory implements ConverterFactory<String, Color>, ConditionalConverter {
private MyConditionalConverter converter = new MyConditionalConverter();
......@@ -768,11 +826,13 @@ public class GenericConversionServiceTests {
String getBaseCode();
}
private static interface MyEnumInterface extends MyEnumBaseInterface {
private interface MyEnumInterface extends MyEnumBaseInterface {
String getCode();
}
private static enum MyEnum implements MyEnumInterface {
private enum MyEnum implements MyEnumInterface {
A("1"),
B("2"),
......@@ -795,7 +855,8 @@ public class GenericConversionServiceTests {
}
}
private static enum EnumWithSubclass {
private enum EnumWithSubclass {
FIRST {
@Override
......@@ -805,6 +866,7 @@ public class GenericConversionServiceTests {
}
}
@SuppressWarnings("rawtypes")
private static class MyStringToRawCollectionConverter implements Converter<String, Collection> {
......@@ -814,6 +876,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringToGenericCollectionConverter implements Converter<String, Collection<?>> {
@Override
......@@ -822,6 +885,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyEnumInterfaceToStringConverter<T extends MyEnumInterface> implements Converter<T, String> {
@Override
......@@ -830,14 +894,16 @@ public class GenericConversionServiceTests {
}
}
private static class StringToMyEnumInterfaceConverterFactory implements ConverterFactory<String, MyEnumInterface> {
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public <T extends MyEnumInterface> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToMyEnumInterfaceConverter(targetType);
}
private static class StringToMyEnumInterfaceConverter<T extends Enum<?> & MyEnumInterface> implements Converter<String, T> {
private final Class<T> enumType;
public StringToMyEnumInterfaceConverter(Class<T> enumType) {
......@@ -855,9 +921,10 @@ public class GenericConversionServiceTests {
}
}
private static class StringToMyEnumBaseInterfaceConverterFactory implements ConverterFactory<String, MyEnumBaseInterface> {
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public <T extends MyEnumBaseInterface> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToMyEnumBaseInterfaceConverter(targetType);
}
......@@ -881,6 +948,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> {
@Override
......@@ -889,6 +957,7 @@ public class GenericConversionServiceTests {
}
}
private static class MyStringToIntegerCollectionConverter implements Converter<String, Collection<Integer>> {
@Override
......@@ -897,6 +966,7 @@ public class GenericConversionServiceTests {
}
}
@SuppressWarnings("rawtypes")
private static class UntypedConverter implements Converter {
......@@ -906,28 +976,27 @@ public class GenericConversionServiceTests {
}
}
private static class ColorConverter implements Converter<String, Color> {
@Override
public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); }
public Color convert(String source) {
return Color.decode(source.trim());
}
}
@ExampleAnnotation
public String annotatedString;
public List<Integer> list;
public Map<String, Integer> map;
public Map<String, ?> wildcardMap;
@SuppressWarnings("rawtypes")
public Collection rawCollection;
public Collection<?> genericCollection;
public Collection<String> stringCollection;
private static class MyConditionalColorConverter implements Converter<String, Color>, ConditionalConverter {
public Collection<Integer> integerCollection;
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
ExampleAnnotation ann = targetType.getAnnotation(ExampleAnnotation.class);
return (ann != null && ann.active());
}
@Override
public Color convert(String source) {
return Color.decode(source.substring(0, 6));
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册