Skip to content

Commit 175f08f

Browse files
committed
Allow default enums with @JsonCreator
This follows the pattern for READ_UNKNOWN_ENUM_VALUES_AS_NULL from here: https://github.com/FasterXML/jackson-databind/pull/1642/files but for READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE It's more tricky because it wasn't immediately apparent how to get the configured default value on the Creator impl side. I decided to try using the EnumResolver, which works, but am not sure what the repercussions of that are fully though. It works the same way, so only IllegalArgumentExceptions will trigger default behavior, so if you have some other custom creator exception logic that will be unaffected.
1 parent d98215c commit 175f08f

File tree

5 files changed

+35
-10
lines changed

5 files changed

+35
-10
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,9 @@ public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
10871087
"Invalid `@JsonCreator` annotated Enum factory method [%s]: needs to return compatible type",
10881088
factory.toString()));
10891089
}
1090-
deser = EnumDeserializer.deserializerForCreator(config, enumClass, factory, valueInstantiator, creatorProps);
1090+
deser = EnumDeserializer.deserializerForCreator(
1091+
config, enumClass, factory, valueInstantiator, creatorProps,
1092+
constructEnumResolver(enumClass, config, beanDesc));
10911093
break;
10921094
}
10931095
}

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public EnumDeserializer(EnumResolver byNameResolver) {
160160
@Deprecated
161161
public static JsonDeserializer<?> deserializerForCreator(DeserializationConfig config,
162162
Class<?> enumClass, AnnotatedMethod factory) {
163-
return deserializerForCreator(config, enumClass, factory, null, null);
163+
return deserializerForCreator(config, enumClass, factory, null, null, null);
164164
}
165165

166166
/**
@@ -172,16 +172,15 @@ public static JsonDeserializer<?> deserializerForCreator(DeserializationConfig c
172172
* @since 2.8
173173
*/
174174
public static JsonDeserializer<?> deserializerForCreator(DeserializationConfig config,
175-
Class<?> enumClass, AnnotatedMethod factory,
176-
ValueInstantiator valueInstantiator, SettableBeanProperty[] creatorProps)
175+
Class<?> enumClass, AnnotatedMethod factory, ValueInstantiator valueInstantiator,
176+
SettableBeanProperty[] creatorProps, EnumResolver byNameResolver)
177177
{
178178
if (config.canOverrideAccessModifiers()) {
179179
ClassUtil.checkAndFixAccess(factory.getMember(),
180180
config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
181181
}
182-
return new FactoryBasedEnumDeserializer(enumClass, factory,
183-
factory.getParameterType(0),
184-
valueInstantiator, creatorProps);
182+
return new FactoryBasedEnumDeserializer(enumClass, factory, factory.getParameterType(0),
183+
valueInstantiator, creatorProps, byNameResolver);
185184
}
186185

187186
/**

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
1616
import com.fasterxml.jackson.databind.type.LogicalType;
1717
import com.fasterxml.jackson.databind.util.ClassUtil;
18+
import com.fasterxml.jackson.databind.util.EnumResolver;
1819

1920
/**
2021
* Deserializer that uses a single-String static factory method
@@ -34,6 +35,7 @@ class FactoryBasedEnumDeserializer
3435
protected final JsonDeserializer<?> _deser;
3536
protected final ValueInstantiator _valueInstantiator;
3637
protected final SettableBeanProperty[] _creatorProps;
38+
protected final Enum<?> _defaultValue;
3739

3840
protected final boolean _hasArgs;
3941

@@ -45,7 +47,8 @@ class FactoryBasedEnumDeserializer
4547
private transient volatile PropertyBasedCreator _propCreator;
4648

4749
public FactoryBasedEnumDeserializer(Class<?> cls, AnnotatedMethod f, JavaType paramType,
48-
ValueInstantiator valueInstantiator, SettableBeanProperty[] creatorProps)
50+
ValueInstantiator valueInstantiator, SettableBeanProperty[] creatorProps,
51+
EnumResolver enumResolver)
4952
{
5053
super(cls);
5154
_factory = f;
@@ -56,6 +59,7 @@ public FactoryBasedEnumDeserializer(Class<?> cls, AnnotatedMethod f, JavaType pa
5659
_deser = null;
5760
_valueInstantiator = valueInstantiator;
5861
_creatorProps = creatorProps;
62+
_defaultValue = enumResolver.getDefaultValue();
5963
}
6064

6165
/**
@@ -70,6 +74,7 @@ public FactoryBasedEnumDeserializer(Class<?> cls, AnnotatedMethod f)
7074
_deser = null;
7175
_valueInstantiator = null;
7276
_creatorProps = null;
77+
_defaultValue = null;
7378
}
7479

7580
protected FactoryBasedEnumDeserializer(FactoryBasedEnumDeserializer base,
@@ -80,6 +85,7 @@ protected FactoryBasedEnumDeserializer(FactoryBasedEnumDeserializer base,
8085
_hasArgs = base._hasArgs;
8186
_valueInstantiator = base._valueInstantiator;
8287
_creatorProps = base._creatorProps;
88+
_defaultValue = base._defaultValue;
8389

8490
_deser = deser;
8591
}
@@ -202,6 +208,10 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
202208
if (ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
203209
return null;
204210
}
211+
212+
if (ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)) {
213+
return _defaultValue;
214+
}
205215
// 12-Oct-2021, tatu: Should probably try to provide better exception since
206216
// we likely hit argument incompatibility... Or can this happen?
207217
}

src/test/java/com/fasterxml/jackson/databind/deser/creators/EnumCreatorTest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ public JsonDeserializer<?> findEnumDeserializer(final Class<?> type, final Deser
125125
for (AnnotatedMethod am : factoryMethods) {
126126
final JsonCreator creator = am.getAnnotation(JsonCreator.class);
127127
if (creator != null) {
128-
return EnumDeserializer.deserializerForCreator(config, type, am, null, null);
128+
return EnumDeserializer.deserializerForCreator(
129+
config, type, am, null, null, null);
129130
}
130131
}
131132
}

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ static enum EnumWithDefaultAnnoAndConstructor {
161161
}
162162

163163
static enum StrictEnumCreator {
164-
A, B;
164+
A, B, @JsonEnumDefaultValue UNKNOWN;
165165

166166
@JsonCreator public static StrictEnumCreator fromId(String value) {
167167
for (StrictEnumCreator e: values()) {
@@ -465,6 +465,19 @@ public void testAllowUnknownEnumValuesReadAsNullWithCreatorMethod() throws Excep
465465
assertNull(reader.forType(StrictEnumCreator.class).readValue(" 4343 "));
466466
}
467467

468+
@Test
469+
public void testAllowUnknownEnumValuesReadAsDefaultWithCreatorMethod() throws Exception
470+
{
471+
ObjectReader reader = MAPPER.reader(
472+
DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
473+
assertEquals(
474+
StrictEnumCreator.UNKNOWN,
475+
reader.forType(StrictEnumCreator.class).readValue("\"NO-SUCH-VALUE\""));
476+
assertEquals(
477+
StrictEnumCreator.UNKNOWN,
478+
reader.forType(StrictEnumCreator.class).readValue(" 4343 "));
479+
}
480+
468481
@Test
469482
public void testAllowUnknownEnumValuesForEnumSets() throws Exception
470483
{

0 commit comments

Comments
 (0)