0

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?

1 Answer 1

1

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().*

Sign up to request clarification or add additional context in comments.

1 Comment

Sad, but looks like it is the only way. Thank you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.