diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 79d135c5484..f284d284c64 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -232,18 +232,8 @@ class TypeConverterDelegate { // It's an empty enum identifier: reset the enum value to null. return null; } - // Try field lookup as fallback: for JDK 1.5 enum or custom enum - // with values defined as static fields. Resulting value still needs - // to be checked, hence we don't return it right away. - try { - Field enumField = requiredType.getField(trimmedValue); - convertedValue = enumField.get(null); - } - catch (Throwable ex) { - if (logger.isTraceEnabled()) { - logger.trace("Field [" + convertedValue + "] isn't an enum value", ex); - } - } + + convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue); } } @@ -270,6 +260,52 @@ class TypeConverterDelegate { return (T) convertedValue; } + private Object attemptToConvertStringToEnum(Class requiredType, String trimmedValue, Object currentConvertedValue) { + Object convertedValue = currentConvertedValue; + + if(Enum.class.equals(requiredType)) { + // target type is declared as raw enum, treat the trimmed value as .FIELD_NAME + int index = trimmedValue.lastIndexOf("."); + if(index > - 1) { + String enumType = trimmedValue.substring(0, index); + String fieldName = trimmedValue.substring(index + 1); + + ClassLoader loader = this.targetObject.getClass().getClassLoader(); + + try { + Class enumValueType = loader.loadClass(enumType); + Field enumField = enumValueType.getField(fieldName); + convertedValue = enumField.get(null); + } catch(ClassNotFoundException ex) { + if(logger.isTraceEnabled()) { + logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex); + } + } + catch (Throwable ex) { + if(logger.isTraceEnabled()) { + logger.trace("Field [" + fieldName + "] isn't an enum value for type [" + enumType + "]", ex); + } + } + } + } + if (convertedValue == currentConvertedValue) { + // Try field lookup as fallback: for JDK 1.5 enum or custom enum + // with values defined as static fields. Resulting value still needs + // to be checked, hence we don't return it right away. + try { + Field enumField = requiredType.getField(trimmedValue); + convertedValue = enumField.get(null); + } + catch (Throwable ex) { + if (logger.isTraceEnabled()) { + logger.trace("Field [" + convertedValue + "] isn't an enum value", ex); + + } + } + } + + return convertedValue; + } /** * Find a default editor for the given type. * @param requiredType the type to find an editor for diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperTests.java index deefc08758f..802a9e8e501 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperTests.java @@ -1462,6 +1462,21 @@ public final class BeanWrapperTests { } } + @Test + public void testGenericEnum() { + EnumConsumer consumer = new EnumConsumer(); + BeanWrapper bw = new BeanWrapperImpl(consumer); + bw.setPropertyValue("enumValue", TestEnum.class.getName() + ".TEST_VALUE"); + assertEquals(TestEnum.TEST_VALUE, consumer.getEnumValue()); + } + + @Test + public void testWildcardedGenericEnum() { + WildcardEnumConsumer consumer = new WildcardEnumConsumer(); + BeanWrapper bw = new BeanWrapperImpl(consumer); + bw.setPropertyValue("enumValue", TestEnum.class.getName() + ".TEST_VALUE"); + assertEquals(TestEnum.TEST_VALUE, consumer.getEnumValue()); + } private static class DifferentTestBean extends TestBean { // class to test naming of beans in a BeanWrapper error message @@ -1747,4 +1762,32 @@ public final class BeanWrapperTests { } } + public static class EnumConsumer { + private Enum enumValue; + + public Enum getEnumValue() { + return enumValue; + } + + public void setEnumValue(Enum enumValue) { + this.enumValue = enumValue; + } + } + + public static class WildcardEnumConsumer { + private Enum enumValue; + + public Enum getEnumValue() { + return enumValue; + } + + public void setEnumValue(Enum enumValue) { + this.enumValue = enumValue; + } + } + + public enum TestEnum { + TEST_VALUE + } + }