Skip to content

Commit 678f31c

Browse files
Siwach16Ajay Siwach
andauthored
Add enum features into JsonFormat.Feature (#3731)
Co-authored-by: Ajay Siwach <tat50037@adobe.com>
1 parent abadc05 commit 678f31c

File tree

3 files changed

+110
-20
lines changed

3 files changed

+110
-20
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,8 @@ public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
17061706
if (deser == null) {
17071707
deser = new EnumDeserializer(constructEnumResolver(enumClass,
17081708
config, beanDesc.findJsonValueAccessor()),
1709-
config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS));
1709+
config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
1710+
);
17101711
}
17111712
}
17121713

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

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.fasterxml.jackson.databind.util.ClassUtil;
2020
import com.fasterxml.jackson.databind.util.CompactStringObjectMap;
2121
import com.fasterxml.jackson.databind.util.EnumResolver;
22+
import java.util.Optional;
2223

2324
/**
2425
* Deserializer class that can deserialize instances of
@@ -53,6 +54,9 @@ public class EnumDeserializer
5354

5455
protected final Boolean _caseInsensitive;
5556

57+
private Boolean _useDefaultValueForUnknownEnum;
58+
private Boolean _useNullForUnknownEnum;
59+
5660
/**
5761
* Marker flag for cases where we expect actual integral value for Enum,
5862
* based on {@code @JsonValue} (and equivalent) annotated accessor.
@@ -77,14 +81,16 @@ public EnumDeserializer(EnumResolver byNameResolver, Boolean caseInsensitive)
7781
/**
7882
* @since 2.9
7983
*/
80-
protected EnumDeserializer(EnumDeserializer base, Boolean caseInsensitive)
84+
protected EnumDeserializer(EnumDeserializer base, Boolean caseInsensitive, Boolean useDefaultValueForUnknownEnum, Boolean useNullForUnknownEnum)
8185
{
8286
super(base);
8387
_lookupByName = base._lookupByName;
8488
_enumsByIndex = base._enumsByIndex;
8589
_enumDefaultValue = base._enumDefaultValue;
8690
_caseInsensitive = caseInsensitive;
8791
_isFromIntValue = base._isFromIntValue;
92+
_useDefaultValueForUnknownEnum = useDefaultValueForUnknownEnum;
93+
_useNullForUnknownEnum = useNullForUnknownEnum;
8894
}
8995

9096
/**
@@ -146,23 +152,26 @@ public static JsonDeserializer<?> deserializerForNoArgsCreator(DeserializationCo
146152
/**
147153
* @since 2.9
148154
*/
149-
public EnumDeserializer withResolved(Boolean caseInsensitive) {
150-
if (Objects.equals(_caseInsensitive, caseInsensitive)) {
155+
public EnumDeserializer withResolved(Boolean caseInsensitive, Boolean useDefaultValueForUnknownEnum, Boolean useNullForUnknownEnum) {
156+
if (Objects.equals(_caseInsensitive, caseInsensitive)
157+
&& Objects.equals(_useDefaultValueForUnknownEnum, useDefaultValueForUnknownEnum)
158+
&& Objects.equals(_useNullForUnknownEnum, useNullForUnknownEnum)) {
151159
return this;
152160
}
153-
return new EnumDeserializer(this, caseInsensitive);
161+
return new EnumDeserializer(this, caseInsensitive, useDefaultValueForUnknownEnum, useNullForUnknownEnum);
154162
}
155163

156164
@Override // since 2.9
157165
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
158166
BeanProperty property) throws JsonMappingException
159167
{
160-
Boolean caseInsensitive = findFormatFeature(ctxt, property, handledType(),
161-
JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
162-
if (caseInsensitive == null) {
163-
caseInsensitive = _caseInsensitive;
164-
}
165-
return withResolved(caseInsensitive);
168+
Boolean caseInsensitive = Optional.ofNullable(findFormatFeature(ctxt, property, handledType(),
169+
JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)).orElse(_caseInsensitive);
170+
Boolean useDefaultValueForUnknownEnum = Optional.ofNullable(findFormatFeature(ctxt, property, handledType(),
171+
JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)).orElse(_useDefaultValueForUnknownEnum);
172+
Boolean useNullForUnknownEnum = Optional.ofNullable(findFormatFeature(ctxt, property, handledType(),
173+
JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)).orElse(_useNullForUnknownEnum);
174+
return withResolved(caseInsensitive, useDefaultValueForUnknownEnum, useNullForUnknownEnum);
166175
}
167176

168177
/*
@@ -262,11 +271,10 @@ protected Object _fromInteger(JsonParser p, DeserializationContext ctxt,
262271
if (index >= 0 && index < _enumsByIndex.length) {
263272
return _enumsByIndex[index];
264273
}
265-
if ((_enumDefaultValue != null)
266-
&& ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)) {
274+
if (useDefaultValueForUnknownEnum(ctxt)) {
267275
return _enumDefaultValue;
268276
}
269-
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
277+
if (!useNullForUnknownEnum(ctxt)) {
270278
return ctxt.handleWeirdNumberValue(_enumClass(), index,
271279
"index value outside legal index range [0..%s]",
272280
_enumsByIndex.length-1);
@@ -291,11 +299,10 @@ private final Object _deserializeAltString(JsonParser p, DeserializationContext
291299
if (name.isEmpty()) { // empty or blank
292300
// 07-Jun-2021, tatu: [databind#3171] Need to consider Default value first
293301
// (alas there's bit of duplication here)
294-
if ((_enumDefaultValue != null)
295-
&& ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)) {
302+
if (useDefaultValueForUnknownEnum(ctxt)) {
296303
return _enumDefaultValue;
297304
}
298-
if (ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
305+
if (useNullForUnknownEnum(ctxt)) {
299306
return null;
300307
}
301308

@@ -346,11 +353,10 @@ private final Object _deserializeAltString(JsonParser p, DeserializationContext
346353
}
347354
}
348355
}
349-
if ((_enumDefaultValue != null)
350-
&& ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)) {
356+
if (useDefaultValueForUnknownEnum(ctxt)) {
351357
return _enumDefaultValue;
352358
}
353-
if (ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
359+
if (useNullForUnknownEnum(ctxt)) {
354360
return null;
355361
}
356362
return ctxt.handleWeirdStringValue(_enumClass(), name,
@@ -384,4 +390,15 @@ protected CompactStringObjectMap _getToStringLookup(DeserializationContext ctxt)
384390
}
385391
return lookup;
386392
}
393+
394+
private boolean useNullForUnknownEnum(DeserializationContext ctxt) {
395+
return Boolean.TRUE.equals(_useNullForUnknownEnum)
396+
|| ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
397+
}
398+
399+
private boolean useDefaultValueForUnknownEnum(DeserializationContext ctxt) {
400+
return (_enumDefaultValue != null)
401+
&& (Boolean.TRUE.equals(_useDefaultValueForUnknownEnum)
402+
|| ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE));
403+
}
387404
}

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.fasterxml.jackson.databind.deser.enums;
22

3+
import com.fasterxml.jackson.core.JsonProcessingException;
34
import java.io.IOException;
45
import java.util.EnumSet;
56

@@ -36,6 +37,25 @@ protected static class StrictCaseBean {
3637
public TestEnum value;
3738
}
3839

40+
protected static class DefaultEnumBean {
41+
@JsonFormat(with={ JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE })
42+
public MyEnum2352_3 value;
43+
}
44+
45+
protected static class DefaultEnumSetBean {
46+
@JsonFormat(with={ JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE })
47+
public EnumSet<MyEnum2352_3> value;
48+
}
49+
50+
protected static class NullValueEnumBean {
51+
@JsonFormat(with={ JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_AS_NULL })
52+
public MyEnum2352_3 value;
53+
}
54+
55+
protected static class NullEnumSetBean {
56+
@JsonFormat(with={ JsonFormat.Feature.READ_UNKNOWN_ENUM_VALUES_AS_NULL })
57+
public EnumSet<MyEnum2352_3> value;
58+
}
3959

4060
// for [databind#2352]: Support aliases on enum values
4161
enum MyEnum2352_1 {
@@ -213,4 +233,56 @@ public void testEnumWithAliasAndDefaultForUnknownValueEnabled() throws Exception
213233
MyEnum2352_3 multipleAliases2 = reader.readValue(q("multipleAliases2"));
214234
assertEquals(MyEnum2352_3.C, multipleAliases2);
215235
}
236+
237+
public void testEnumWithDefaultForUnknownValueEnabled() throws Exception {
238+
final String JSON = a2q("{'value':'ok'}");
239+
240+
DefaultEnumBean pojo = READER_DEFAULT.forType(DefaultEnumBean.class)
241+
.readValue(JSON);
242+
assertEquals(MyEnum2352_3.B, pojo.value);
243+
// including disabling acceptance
244+
try {
245+
READER_DEFAULT.forType(StrictCaseBean.class)
246+
.readValue(JSON);
247+
fail("Should not pass");
248+
} catch (InvalidFormatException e) {
249+
verifyException(e, "not one of the values accepted for Enum class");
250+
verifyException(e, "[JACKSON, OK, RULES]");
251+
}
252+
}
253+
254+
public void testEnumWithNullForUnknownValueEnabled() throws Exception {
255+
final String JSON = a2q("{'value':'ok'}");
256+
257+
NullValueEnumBean pojo = READER_DEFAULT.forType(NullValueEnumBean.class)
258+
.readValue(JSON);
259+
assertNull(pojo.value);
260+
// including disabling acceptance
261+
try {
262+
READER_DEFAULT.forType(StrictCaseBean.class)
263+
.readValue(JSON);
264+
fail("Should not pass");
265+
} catch (InvalidFormatException e) {
266+
verifyException(e, "not one of the values accepted for Enum class");
267+
verifyException(e, "[JACKSON, OK, RULES]");
268+
}
269+
}
270+
271+
public void testEnumWithDefaultForUnknownValueEnumSet() throws Exception {
272+
final String JSON = a2q("{'value':['ok']}");
273+
274+
DefaultEnumSetBean pojo = READER_DEFAULT.forType(DefaultEnumSetBean.class)
275+
.readValue(JSON);
276+
assertEquals(1, pojo.value.size());
277+
assertTrue(pojo.value.contains(MyEnum2352_3.B));
278+
}
279+
280+
public void testEnumWithNullForUnknownValueEnumSet() throws Exception {
281+
final String JSON = a2q("{'value':['ok','B']}");
282+
283+
NullEnumSetBean pojo = READER_DEFAULT.forType(NullEnumSetBean.class)
284+
.readValue(JSON);
285+
assertEquals(1, pojo.value.size());
286+
assertTrue(pojo.value.contains(MyEnum2352_3.B));
287+
}
216288
}

0 commit comments

Comments
 (0)