Change GenericConversionService to better handle enum
Prior to this commit, given an enum which implements some interface, GenericConversionService would select the String -> Enum converter even if a converter for String -> SomeInterface was registered. This also affected converters that were registered for String -> SomeBaseInterface, when SomeInterface extended SomeBaseInterface. This change modifies the behavior of the private method getClassHierarchy() by placing Enum.class as late as possible, pretty much the same way as Object.class is handled. Issue: SPR-12050
This commit is contained in:
committed by
Stephane Nicoll
parent
ebc5fea77b
commit
d0e6f0f73f
@@ -57,6 +57,7 @@ import static org.junit.Assert.*;
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author David Haraburda
|
||||
*/
|
||||
public class GenericConversionServiceTests {
|
||||
|
||||
@@ -758,6 +759,20 @@ public class GenericConversionServiceTests {
|
||||
assertEquals("1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringToEnumWithInterfaceConversion() {
|
||||
conversionService.addConverterFactory(new StringToEnumConverterFactory());
|
||||
conversionService.addConverterFactory(new StringToMyEnumInterfaceConverterFactory());
|
||||
assertEquals(MyEnum.A, conversionService.convert("1", MyEnum.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringToEnumWithBaseInterfaceConversion() {
|
||||
conversionService.addConverterFactory(new StringToEnumConverterFactory());
|
||||
conversionService.addConverterFactory(new StringToMyEnumBaseInterfaceConverterFactory());
|
||||
assertEquals(MyEnum.A, conversionService.convert("base1", MyEnum.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertNullAnnotatedStringToString() throws Exception {
|
||||
DefaultConversionService.addDefaultConverters(conversionService);
|
||||
@@ -930,19 +945,34 @@ public class GenericConversionServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
interface MyEnumBaseInterface {
|
||||
String getBaseCode();
|
||||
}
|
||||
|
||||
interface MyEnumInterface {
|
||||
|
||||
interface MyEnumInterface extends MyEnumBaseInterface {
|
||||
String getCode();
|
||||
}
|
||||
|
||||
public static enum MyEnum implements MyEnumInterface {
|
||||
|
||||
A {
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "1";
|
||||
}
|
||||
A("1"),
|
||||
B("2"),
|
||||
C("3");
|
||||
|
||||
private String code;
|
||||
|
||||
MyEnum(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseCode() {
|
||||
return "base" + code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,6 +1001,59 @@ public class GenericConversionServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringToMyEnumInterfaceConverterFactory implements ConverterFactory<String, MyEnumInterface> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
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) {
|
||||
this.enumType = enumType;
|
||||
}
|
||||
|
||||
public T convert(String source) {
|
||||
for (T value : enumType.getEnumConstants()) {
|
||||
if (value.getCode().equals(source)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class StringToMyEnumBaseInterfaceConverterFactory implements ConverterFactory<String, MyEnumBaseInterface> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends MyEnumBaseInterface> Converter<String, T> getConverter(Class<T> targetType) {
|
||||
return new StringToMyEnumBaseInterfaceConverter(targetType);
|
||||
}
|
||||
|
||||
private static class StringToMyEnumBaseInterfaceConverter<T extends Enum<?> & MyEnumBaseInterface> implements Converter<String, T> {
|
||||
private final Class<T> enumType;
|
||||
|
||||
public StringToMyEnumBaseInterfaceConverter(Class<T> enumType) {
|
||||
this.enumType = enumType;
|
||||
}
|
||||
|
||||
public T convert(String source) {
|
||||
for (T value : enumType.getEnumConstants()) {
|
||||
if (value.getBaseCode().equals(source)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> {
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user