diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java index 468258d74c..8e74dcd611 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java @@ -106,6 +106,14 @@ public enum DeserializationFeature implements ConfigFeature */ READ_ENUMS_USING_TO_STRING(false), + /** + * Feature that determines if Enum deserialization should be case sensitive or not. + * If enabled, Enum deserialization will ignore case. + *
+ * Feature is disabled by default. + */ + READ_ENUMS_IGNORING_CASE(false), + /* /****************************************************** * Error handling features diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java index 3c65723aa5..7e394b41d4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java @@ -167,6 +167,13 @@ private final Object _deserializeAltString(JsonParser p, DeserializationContext if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)) { return null; } + } else if (ctxt.isEnabled(DeserializationFeature.READ_ENUMS_IGNORING_CASE)) { + // [databind#1313]: Case insensitive enum deserialization + for (String key : lookup.keys()) { + if (key.equalsIgnoreCase(name)) { + return lookup.find(key); + } + } } else if (!ctxt.isEnabled(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)) { // [databind#149]: Allow use of 'String' indexes as well -- unless prohibited (as per above) char c = name.charAt(0); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/EnumDeserializationTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/EnumDeserializationTest.java index b2fbbcbb4b..61e8132185 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/EnumDeserializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/EnumDeserializationTest.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.fasterxml.jackson.databind.module.SimpleModule; @SuppressWarnings("serial") @@ -510,4 +511,56 @@ public void testExceptionFromCustomEnumKeyDeserializer() { assertTrue(e.getMessage().contains("Undefined AnEnum")); } } + + public void testFailWhenCaseSensitiveAndNameIsNotUpperCase() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + + try { + objectMapper.readValue("\"Jackson\"", TestEnum.class); + fail("InvalidFormatException expected"); + } catch (InvalidFormatException e) { + assertTrue(e.getMessage().contains("value not one of declared Enum instance names: [JACKSON, OK, RULES]")); + } + } + + public void testFailWhenCaseSensitiveAndToStringIsUpperCase() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + + try { + objectMapper.readValue("\"A\"", LowerCaseEnum.class); + fail("InvalidFormatException expected"); + } catch (InvalidFormatException e) { + assertTrue(e.getMessage().contains("value not one of declared Enum instance names: [a, b, c]")); + } + } + + public void testEnumDesIgnoringCaseWithLowerCaseContent() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(DeserializationFeature.READ_ENUMS_IGNORING_CASE); + + TestEnum testEnum = objectMapper.readValue("\"jackson\"", TestEnum.class); + + assertEquals(TestEnum.JACKSON, testEnum); + } + + public void testEnumDesIgnoringCaseWithUpperCaseToString() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + objectMapper.enable(DeserializationFeature.READ_ENUMS_IGNORING_CASE); + + LowerCaseEnum lowerCaseEnum = objectMapper.readValue("\"A\"", LowerCaseEnum.class); + + assertEquals(LowerCaseEnum.A, lowerCaseEnum); + } + + public void testIgnoreCaseInEnumList() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(DeserializationFeature.READ_ENUMS_IGNORING_CASE); + + TestEnum[] testEnum = objectMapper.readValue("[\"jackson\", \"rules\"]", TestEnum[].class); + + assertEquals(TestEnum.JACKSON, testEnum[0]); + assertEquals(TestEnum.RULES, testEnum[1]); + } }