Skip to content

Commit c299371

Browse files
committed
Merge pull request #607 from dharaburda/SPR-12050
* SPR-12050: Change GenericConversionService to better handle enum
2 parents ebc5fea + d0e6f0f commit c299371

File tree

2 files changed

+107
-11
lines changed

2 files changed

+107
-11
lines changed

spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* @author Juergen Hoeller
5656
* @author Chris Beams
5757
* @author Phillip Webb
58+
* @author David Haraburda
5859
* @since 3.0
5960
*/
6061
public class GenericConversionService implements ConfigurableConversionService {
@@ -567,19 +568,31 @@ private List<Class<?>> getClassHierarchy(Class<?> type) {
567568
Class<?> candidate = hierarchy.get(i);
568569
candidate = (array ? candidate.getComponentType() : ClassUtils.resolvePrimitiveIfNecessary(candidate));
569570
Class<?> superclass = candidate.getSuperclass();
570-
if (candidate.getSuperclass() != null && superclass != Object.class) {
571+
if (candidate.getSuperclass() != null && superclass != Object.class && superclass != Enum.class) {
571572
addToClassHierarchy(i + 1, candidate.getSuperclass(), array, hierarchy, visited);
572573
}
573-
for (Class<?> implementedInterface : candidate.getInterfaces()) {
574-
addToClassHierarchy(hierarchy.size(), implementedInterface, array, hierarchy, visited);
575-
}
574+
addInterfacesToClassHierarchy(candidate, array, hierarchy, visited);
576575
i++;
577576
}
577+
578+
if (type.isEnum()) {
579+
addToClassHierarchy(hierarchy.size(), Enum.class, array, hierarchy, visited);
580+
addToClassHierarchy(hierarchy.size(), Enum.class, false, hierarchy, visited);
581+
addInterfacesToClassHierarchy(Enum.class, array, hierarchy, visited);
582+
}
583+
578584
addToClassHierarchy(hierarchy.size(), Object.class, array, hierarchy, visited);
579585
addToClassHierarchy(hierarchy.size(), Object.class, false, hierarchy, visited);
580586
return hierarchy;
581587
}
582588

589+
private void addInterfacesToClassHierarchy(Class<?> type, boolean asArray,
590+
List<Class<?>> hierarchy, Set<Class<?>> visited) {
591+
for (Class<?> implementedInterface : type.getInterfaces()) {
592+
addToClassHierarchy(hierarchy.size(), implementedInterface, asArray, hierarchy, visited);
593+
}
594+
}
595+
583596
private void addToClassHierarchy(int index, Class<?> type, boolean asArray,
584597
List<Class<?>> hierarchy, Set<Class<?>> visited) {
585598
if (asArray) {

spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
* @author Keith Donald
5858
* @author Juergen Hoeller
5959
* @author Phillip Webb
60+
* @author David Haraburda
6061
*/
6162
public class GenericConversionServiceTests {
6263

@@ -758,6 +759,20 @@ public void testEnumWithInterfaceToStringConversion() {
758759
assertEquals("1", result);
759760
}
760761

762+
@Test
763+
public void testStringToEnumWithInterfaceConversion() {
764+
conversionService.addConverterFactory(new StringToEnumConverterFactory());
765+
conversionService.addConverterFactory(new StringToMyEnumInterfaceConverterFactory());
766+
assertEquals(MyEnum.A, conversionService.convert("1", MyEnum.class));
767+
}
768+
769+
@Test
770+
public void testStringToEnumWithBaseInterfaceConversion() {
771+
conversionService.addConverterFactory(new StringToEnumConverterFactory());
772+
conversionService.addConverterFactory(new StringToMyEnumBaseInterfaceConverterFactory());
773+
assertEquals(MyEnum.A, conversionService.convert("base1", MyEnum.class));
774+
}
775+
761776
@Test
762777
public void convertNullAnnotatedStringToString() throws Exception {
763778
DefaultConversionService.addDefaultConverters(conversionService);
@@ -930,19 +945,34 @@ public int getNestedMatchAttempts() {
930945
}
931946
}
932947

948+
interface MyEnumBaseInterface {
949+
String getBaseCode();
950+
}
933951

934-
interface MyEnumInterface {
935-
952+
interface MyEnumInterface extends MyEnumBaseInterface {
936953
String getCode();
937954
}
938955

939956
public static enum MyEnum implements MyEnumInterface {
940957

941-
A {
942-
@Override
943-
public String getCode() {
944-
return "1";
945-
}
958+
A("1"),
959+
B("2"),
960+
C("3");
961+
962+
private String code;
963+
964+
MyEnum(String code) {
965+
this.code = code;
966+
}
967+
968+
@Override
969+
public String getCode() {
970+
return code;
971+
}
972+
973+
@Override
974+
public String getBaseCode() {
975+
return "base" + code;
946976
}
947977
}
948978

@@ -971,6 +1001,59 @@ public String convert(T source) {
9711001
}
9721002
}
9731003

1004+
private static class StringToMyEnumInterfaceConverterFactory implements ConverterFactory<String, MyEnumInterface> {
1005+
1006+
@SuppressWarnings("unchecked")
1007+
public <T extends MyEnumInterface> Converter<String, T> getConverter(Class<T> targetType) {
1008+
return new StringToMyEnumInterfaceConverter(targetType);
1009+
}
1010+
1011+
private static class StringToMyEnumInterfaceConverter<T extends Enum<?> & MyEnumInterface> implements Converter<String, T> {
1012+
private final Class<T> enumType;
1013+
1014+
public StringToMyEnumInterfaceConverter(Class<T> enumType) {
1015+
this.enumType = enumType;
1016+
}
1017+
1018+
public T convert(String source) {
1019+
for (T value : enumType.getEnumConstants()) {
1020+
if (value.getCode().equals(source)) {
1021+
return value;
1022+
}
1023+
}
1024+
return null;
1025+
}
1026+
}
1027+
1028+
}
1029+
1030+
private static class StringToMyEnumBaseInterfaceConverterFactory implements ConverterFactory<String, MyEnumBaseInterface> {
1031+
1032+
@SuppressWarnings("unchecked")
1033+
public <T extends MyEnumBaseInterface> Converter<String, T> getConverter(Class<T> targetType) {
1034+
return new StringToMyEnumBaseInterfaceConverter(targetType);
1035+
}
1036+
1037+
private static class StringToMyEnumBaseInterfaceConverter<T extends Enum<?> & MyEnumBaseInterface> implements Converter<String, T> {
1038+
private final Class<T> enumType;
1039+
1040+
public StringToMyEnumBaseInterfaceConverter(Class<T> enumType) {
1041+
this.enumType = enumType;
1042+
}
1043+
1044+
public T convert(String source) {
1045+
for (T value : enumType.getEnumConstants()) {
1046+
if (value.getBaseCode().equals(source)) {
1047+
return value;
1048+
}
1049+
}
1050+
return null;
1051+
}
1052+
}
1053+
1054+
}
1055+
1056+
9741057
public static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> {
9751058

9761059
@Override

0 commit comments

Comments
 (0)