There is a record class in which one of the properties is an enum field.
The results of deserialization differ from what I'm looking for. Obviously, when the field is null or absent Jackson does not use the @JsonCreator
method and just inserts null.
I would like to avoid that "special treatment" and deserialize nulls (and field absence as well) the same way as other values.
Model classes
record MyRec(
String first,
Color second
){}
// ---
enum Color{
RED, GREEN;
@JsonCreator
static Color fromName(String name){
if (name == null || "red".equals(name)){
return RED;
} else if ("green".equals(name)) {
return GREEN;
} else {
throw new IllegalArgumentException(name);
}
}
}
Results of deserialization
JSON actual intent
------------------------------------|-------------------|------------------|------
'{"first": "hi", "second": "red"}' MyRec("hi", RED) MyRec("hi", RED) | ok
'{"first": "hi", "second": null}' MyRec("hi", null) MyRec("hi", RED) | ?
'{"first": "hi"}' MyRec("hi", null) MyRec("hi", RED) | ?
How to force Jackson to use the @JsonCreator
method for deserializing nulls and absent values?
You can define an overloaded constructor in your record delegating to the canonical constructor via call this()
, and annotate it with @JsonCreator
(otherwise, Jackson would use the canonical one).
The attribute second
can be received as a plain String
and parsed using the method fromName()
you've defined in the enum
:
record MyRec(String first, Color second) {
@JsonCreator
public MyRec(@JsonProperty("first") String first,
@JsonProperty("second") String second) {
this(first, Color.fromName(second));
}
}
Note: no data-binding annotations required in your enum
.
Usage example:
public static void main(String[] args) throws JsonProcessingException {
List<String> jsonRecords = List.of(
"""
{"first": "hi", "second": "red"}""",
"""
{"first": "hi", "second": null}""",
"""
{"first": "hi"}"""
);
ObjectMapper mapper1 = new JsonMapper();
List<MyRec> records = new ArrayList<>();
for (String json : jsonRecords) {
MyRec myRec = mapper1.readValue(json, MyRec.class);
records.add(myRec);
}
records.forEach(System.out::println);
}
Output:
MyRec[first=hi, second=RED]
MyRec[first=hi, second=RED]
MyRec[first=hi, second=RED]
Sidenote: possibly you might want to use equalsIgnoreCase()
instead of plain equals()
.*