Skip to content

Commit 3711a1c

Browse files
committed
Minor tweak to #1520: move case-insensitive feature as MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS
1 parent 6eb32dc commit 3711a1c

File tree

9 files changed

+50
-119
lines changed

9 files changed

+50
-119
lines changed

release-notes/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Project: jackson-databind
6262
#1474: Replace use of `Class.newInstance()` (deprecated in Java 9) with call via Constructor
6363
#1480: Add support for serializing `boolean`/`Boolean` as number (0 or 1)
6464
(suggested by jwilmoth@github)
65-
#1520: Case insensitive enum deserialization feature.
65+
#1520: Case insensitive enum deserialization with `MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS`
6666
(contributed by Ana-Eliza B)
6767
#1544: EnumMapDeserializer assumes a pure EnumMap and does not support EnumMap derived classes
6868
(reported by Lyor G)

src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java

-12
Original file line numberDiff line numberDiff line change
@@ -365,18 +365,6 @@ public enum DeserializationFeature implements ConfigFeature
365365
*/
366366
READ_ENUMS_USING_TO_STRING(false),
367367

368-
/**
369-
* Feature that determines if Enum deserialization should be case sensitive or not.
370-
* If enabled, Enum deserialization will ignore case, that is, case of incoming String
371-
* value and enum id (dependant on other settings, either `name()`, `toString()`, or
372-
* explicit override) do not need to match.
373-
* <p>
374-
* Feature is disabled by default.
375-
*
376-
* @since 2.9
377-
*/
378-
READ_ENUMS_IGNORING_CASE(false),
379-
380368
/**
381369
* Feature that allows unknown Enum values to be parsed as null values.
382370
* If disabled, unknown Enum values will throw exceptions.

src/main/java/com/fasterxml/jackson/databind/MapperFeature.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ public enum MapperFeature implements ConfigFeature
338338
/* Name-related features
339339
/******************************************************
340340
*/
341+
341342
/**
342343
* Feature that will allow for more forgiving deserialization of incoming JSON.
343344
* If enabled, the bean properties will be matched using their lower-case equivalents,
@@ -353,7 +354,20 @@ public enum MapperFeature implements ConfigFeature
353354
* @since 2.5
354355
*/
355356
ACCEPT_CASE_INSENSITIVE_PROPERTIES(false),
356-
357+
358+
359+
/**
360+
* Feature that determines if Enum deserialization should be case sensitive or not.
361+
* If enabled, Enum deserialization will ignore case, that is, case of incoming String
362+
* value and enum id (dependant on other settings, either `name()`, `toString()`, or
363+
* explicit override) do not need to match.
364+
* <p>
365+
* Feature is disabled by default.
366+
*
367+
* @since 2.9
368+
*/
369+
ACCEPT_CASE_INSENSITIVE_ENUMS(false),
370+
357371
/**
358372
* Feature that can be enabled to make property names be
359373
* overridden by wrapper name (usually detected with annotations

src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,8 @@ public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
12761276
// Need to consider @JsonValue if one found
12771277
if (deser == null) {
12781278
deser = new EnumDeserializer(constructEnumResolver(enumClass,
1279-
config, beanDesc.findJsonValueAccessor()));
1279+
config, beanDesc.findJsonValueAccessor()),
1280+
config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS));
12801281
}
12811282
}
12821283

src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,16 @@ public class EnumDeserializer
4949

5050
protected final Boolean _caseInsensitive;
5151

52-
public EnumDeserializer(EnumResolver byNameResolver)
52+
/**
53+
* @since 2.9
54+
*/
55+
public EnumDeserializer(EnumResolver byNameResolver, Boolean caseInsensitive)
5356
{
5457
super(byNameResolver.getEnumClass());
5558
_lookupByName = byNameResolver.constructLookup();
5659
_enumsByIndex = byNameResolver.getRawEnums();
5760
_enumDefaultValue = byNameResolver.getDefaultValue();
58-
_caseInsensitive = false;
61+
_caseInsensitive = caseInsensitive;
5962
}
6063

6164
/**
@@ -70,6 +73,14 @@ protected EnumDeserializer(EnumDeserializer base, Boolean caseInsensitive)
7073
_caseInsensitive = caseInsensitive;
7174
}
7275

76+
/**
77+
* @deprecated Since 2.9
78+
*/
79+
@Deprecated
80+
public EnumDeserializer(EnumResolver byNameResolver) {
81+
this(byNameResolver, null);
82+
}
83+
7384
/**
7485
* @deprecated Since 2.8
7586
*/
@@ -134,6 +145,9 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
134145
{
135146
Boolean caseInsensitive = findFormatFeature(ctxt, property, handledType(),
136147
JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
148+
if (caseInsensitive == null) {
149+
caseInsensitive = _caseInsensitive;
150+
}
137151
return withResolved(caseInsensitive);
138152
}
139153

@@ -208,9 +222,7 @@ private final Object _deserializeAltString(JsonParser p, DeserializationContext
208222
}
209223
} else {
210224
// [databind#1313]: Case insensitive enum deserialization
211-
if ((_caseInsensitive == Boolean.TRUE) ||
212-
((_caseInsensitive == null) &&
213-
ctxt.isEnabled(DeserializationFeature.READ_ENUMS_IGNORING_CASE))) {
225+
if (Boolean.TRUE.equals(_caseInsensitive)) {
214226
Object match = lookup.findCaseInsensitive(name);
215227
if (match != null) {
216228
return match;

src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java

+4-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package com.fasterxml.jackson.databind.deser.std;
22

33
import java.io.IOException;
4-
import java.lang.reflect.InvocationTargetException;
54

65
import com.fasterxml.jackson.core.JsonParser;
76
import com.fasterxml.jackson.core.JsonProcessingException;
87
import com.fasterxml.jackson.core.JsonToken;
9-
import com.fasterxml.jackson.databind.BeanProperty;
10-
import com.fasterxml.jackson.databind.DeserializationConfig;
11-
import com.fasterxml.jackson.databind.DeserializationContext;
12-
import com.fasterxml.jackson.databind.DeserializationFeature;
13-
import com.fasterxml.jackson.databind.JavaType;
14-
import com.fasterxml.jackson.databind.JsonDeserializer;
15-
import com.fasterxml.jackson.databind.JsonMappingException;
16-
import com.fasterxml.jackson.databind.MapperFeature;
8+
9+
import com.fasterxml.jackson.databind.*;
1710
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
1811
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
1912
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
@@ -197,14 +190,11 @@ public void wrapAndThrow(Throwable t, Object bean, String fieldName, Deserializa
197190

198191
private Throwable throwOrReturnThrowable(Throwable t, DeserializationContext ctxt) throws IOException
199192
{
200-
while (t instanceof InvocationTargetException && t.getCause() != null) {
201-
t = t.getCause();
202-
}
193+
t = ClassUtil.getRootCause(t);
203194
// Errors to be passed as is
204195
ClassUtil.throwIfError(t);
205196
boolean wrap = (ctxt == null) || ctxt.isEnabled(DeserializationFeature.WRAP_EXCEPTIONS);
206-
// Ditto for IOExceptions; except we may want to wrap JSON
207-
// exceptions
197+
// Ditto for IOExceptions; except we may want to wrap JSON exceptions
208198
if (t instanceof IOException) {
209199
if (!wrap || !(t instanceof JsonProcessingException)) {
210200
throw (IOException) t;

src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java

+1-65
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,8 @@ public final class ClassUtil
1818

1919
private final static Annotation[] NO_ANNOTATIONS = new Annotation[0];
2020
private final static Ctor[] NO_CTORS = new Ctor[0];
21-
22-
/*
23-
/**********************************************************
24-
/* Helper classes
25-
/**********************************************************
26-
*/
2721

28-
/* 21-Feb-2016, tatu: Unfortunately `Collections.emptyIterator()` only
29-
* comes with JDK7, so we'll still have to include our bogus implementation
30-
* for as long as we want JDK6 runtime compatibility
31-
*/
32-
private final static class EmptyIterator<T> implements Iterator<T> {
33-
@Override public boolean hasNext() { return false; }
34-
@Override public T next() { throw new NoSuchElementException(); }
35-
@Override public void remove() { throw new UnsupportedOperationException(); }
36-
}
37-
38-
private final static EmptyIterator<?> EMPTY_ITERATOR = new EmptyIterator<Object>();
22+
private final static Iterator<?> EMPTY_ITERATOR = Collections.emptyIterator();
3923

4024
/*
4125
/**********************************************************
@@ -48,8 +32,6 @@ private final static class EmptyIterator<T> implements Iterator<T> {
4832
*/
4933
@SuppressWarnings("unchecked")
5034
public static <T> Iterator<T> emptyIterator() {
51-
// 21-Feb-2016, tatu: As per above, use a locally defined empty iterator
52-
// return Collections.emptyIterator();
5335
return (Iterator<T>) EMPTY_ITERATOR;
5436
}
5537

@@ -328,52 +310,6 @@ public static void verifyMustOverride(Class<?> expType, Object instance,
328310
instance.getClass().getName(), expType.getName(), method));
329311
}
330312
}
331-
332-
/*
333-
/**********************************************************
334-
/* Class loading
335-
/**********************************************************
336-
*/
337-
338-
/**
339-
* @deprecated Since 2.6, use method in {@link com.fasterxml.jackson.databind.type.TypeFactory}.
340-
*/
341-
@Deprecated
342-
public static Class<?> findClass(String className) throws ClassNotFoundException
343-
{
344-
// [JACKSON-597]: support primitive types (and void)
345-
if (className.indexOf('.') < 0) {
346-
if ("int".equals(className)) return Integer.TYPE;
347-
if ("long".equals(className)) return Long.TYPE;
348-
if ("float".equals(className)) return Float.TYPE;
349-
if ("double".equals(className)) return Double.TYPE;
350-
if ("boolean".equals(className)) return Boolean.TYPE;
351-
if ("byte".equals(className)) return Byte.TYPE;
352-
if ("char".equals(className)) return Character.TYPE;
353-
if ("short".equals(className)) return Short.TYPE;
354-
if ("void".equals(className)) return Void.TYPE;
355-
}
356-
// Two-phase lookup: first using context ClassLoader; then default
357-
Throwable prob = null;
358-
ClassLoader loader = Thread.currentThread().getContextClassLoader();
359-
360-
if (loader != null) {
361-
try {
362-
return Class.forName(className, true, loader);
363-
} catch (Exception e) {
364-
prob = getRootCause(e);
365-
}
366-
}
367-
try {
368-
return Class.forName(className);
369-
} catch (Exception e) {
370-
if (prob == null) {
371-
prob = getRootCause(e);
372-
}
373-
}
374-
throwIfRTE(prob);
375-
throw new ClassNotFoundException(prob.getMessage(), prob);
376-
}
377313

378314
/*
379315
/**********************************************************

src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumAltIdTest.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.core.type.TypeReference;
88
import com.fasterxml.jackson.databind.BaseMapTest;
99
import com.fasterxml.jackson.databind.DeserializationFeature;
10+
import com.fasterxml.jackson.databind.MapperFeature;
1011
import com.fasterxml.jackson.databind.ObjectMapper;
1112
import com.fasterxml.jackson.databind.ObjectReader;
1213
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
@@ -40,11 +41,15 @@ protected static class StrictCaseBean {
4041
*/
4142

4243
protected final ObjectMapper MAPPER = new ObjectMapper();
44+
protected final ObjectMapper MAPPER_IGNORE_CASE;
45+
{
46+
MAPPER_IGNORE_CASE = new ObjectMapper();
47+
MAPPER_IGNORE_CASE.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
48+
}
4349

4450
protected final ObjectReader READER_DEFAULT = MAPPER.reader();
45-
protected final ObjectReader READER_IGNORE_CASE = MAPPER
46-
.reader(DeserializationFeature.READ_ENUMS_IGNORING_CASE);
47-
51+
protected final ObjectReader READER_IGNORE_CASE = MAPPER_IGNORE_CASE.reader();
52+
4853
// Tests for [databind#1313], case-insensitive
4954

5055
public void testFailWhenCaseSensitiveAndNameIsNotUpperCase() throws IOException {
@@ -73,9 +78,8 @@ public void testEnumDesIgnoringCaseWithLowerCaseContent() throws IOException {
7378
}
7479

7580
public void testEnumDesIgnoringCaseWithUpperCaseToString() throws IOException {
76-
ObjectReader r = MAPPER.readerFor(LowerCaseEnum.class)
77-
.with(DeserializationFeature.READ_ENUMS_USING_TO_STRING,
78-
DeserializationFeature.READ_ENUMS_IGNORING_CASE);
81+
ObjectReader r = MAPPER_IGNORE_CASE.readerFor(LowerCaseEnum.class)
82+
.with(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
7983
assertEquals(LowerCaseEnum.A, r.readValue("\"A\""));
8084
}
8185

src/test/java/com/fasterxml/jackson/databind/util/ClassUtilTest.java

-14
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,4 @@ public void testDescs()
200200
assertEquals(exp, ClassUtil.getClassDescription("foo"));
201201
assertEquals(exp, ClassUtil.getClassDescription(String.class));
202202
}
203-
204-
@SuppressWarnings("deprecation")
205-
public void testFindClass() throws Exception
206-
{
207-
assertEquals(Integer.TYPE, ClassUtil.findClass("int"));
208-
assertEquals(Long.TYPE, ClassUtil.findClass("long"));
209-
assertEquals(Byte.TYPE, ClassUtil.findClass("byte"));
210-
assertEquals(Short.TYPE, ClassUtil.findClass("short"));
211-
assertEquals(Character.TYPE, ClassUtil.findClass("char"));
212-
assertEquals(Float.TYPE, ClassUtil.findClass("float"));
213-
assertEquals(Double.TYPE, ClassUtil.findClass("double"));
214-
assertEquals(Boolean.TYPE, ClassUtil.findClass("boolean"));
215-
assertEquals(Void.TYPE, ClassUtil.findClass("void"));
216-
}
217203
}

0 commit comments

Comments
 (0)