diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index 95a2ef772ccd..ecd602310f0f 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -351,7 +351,7 @@ else if (componentType.isInterface()) { return converter; } Class superClass = currentClass.getSuperclass(); - if (superClass != null && superClass != Object.class) { + if (superClass != null && superClass != Object.class && superClass != Enum.class) { classQueue.addFirst(superClass); } for (Class interfaceType : currentClass.getInterfaces()) { @@ -365,6 +365,14 @@ else if (componentType.isInterface()) { return converter; } } + if (sourceObjectType.isEnum()) { + Map, MatchableConverters> converters = getTargetConvertersForSource(Enum.class); + GenericConverter converter = getMatchingConverterForTarget(sourceType, targetType, converters); + if (converter != null) { + return converter; + } + } + Map, MatchableConverters> objectConverters = getTargetConvertersForSource(Object.class); return getMatchingConverterForTarget(sourceType, targetType, objectConverters); } @@ -430,7 +438,7 @@ else if (componentType.isInterface()) { return converter; } Class superClass = currentClass.getSuperclass(); - if (superClass != null && superClass != Object.class) { + if (superClass != null && superClass != Object.class && superClass != Enum.class) { classQueue.addFirst(superClass); } for (Class interfaceType : currentClass.getInterfaces()) { @@ -444,6 +452,12 @@ else if (componentType.isInterface()) { return converter; } } + if (targetObjectType.isEnum()) { + GenericConverter converter = matchConverter(converters.get(Enum.class), sourceType, targetType); + if (converter != null) { + return converter; + } + } return matchConverter(converters.get(Object.class), sourceType, targetType); } } diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java index 454c044d2201..a220ba38d82f 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java @@ -43,6 +43,7 @@ import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; 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; @@ -589,5 +590,80 @@ public void testConvertiblePairDifferentEqualsAndHash() throws Exception { assertFalse(pair.equals(pairOpposite)); assertFalse(pair.hashCode() == pairOpposite.hashCode()); } + + // SPR-9692 + @Test + public void testStringToEnumWithInterfaceConversion() { + conversionService.addConverterFactory(new StringToEnumConverterFactory()); + conversionService.addConverterFactory(new StringToMyEnumInterfaceConverterFactory()); + MyEnum result = conversionService.convert("1", MyEnum.class); + assertEquals(MyEnum.A, result); + } + + @Test + public void testEnumWithInterfaceToStringConversion() { + conversionService.addConverter(new EnumToStringConverter()); + conversionService.addConverter(new MyEnumInterfaceToStringConverter()); + String result = conversionService.convert(MyEnum.A, String.class); + assertEquals("1", result); + } + + interface MyEnumInterface { + String getCode(); + } + + public static enum MyEnum implements MyEnumInterface { + A("1"), B("2"); + + private String code; + + MyEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + } + + public static class MyEnumInterfaceToStringConverter implements Converter { + public String convert(T source) { + return source.getCode(); + } + } + + public static class StringToMyEnumInterfaceConverterFactory implements ConverterFactory { + + public Converter getConverter(Class targetType) { + return new StringToMyEnumInterfaceConverter(targetType); + } + + private static class StringToMyEnumInterfaceConverter implements Converter { + private final Class enumType; + public StringToMyEnumInterfaceConverter(Class 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 StringToMyEnumInterfaceConverter implements Converter { + public MyEnumInterface convert(String source) { + for (MyEnumInterface value : MyEnum.values()) { + if (value.getCode().equals(source)) { + return value; + } + } + return null; + } + } }