Search code examples
javajacksonobjectmapper

Deserialise enum field with Jackson


I have a simple enum Days

public enum Days {
    @JsonProperty("Monday")
    MONDAY("Monday"),
    @JsonProperty("Tuesday")
    TUESDAY("Tuesday");

    private String day;

    Days(String day) {
        this.day = day;
    }

    @JsonValue
    public String getDay() {
        return day;
    }
}

and a class Event

public class Event {
    private Days day;
    private String name;


    @JsonCreator
    public Event(@JsonProperty("day") Days day,
             @JsonProperty("name") String name) {
    this.day = day;
    this.name = name;
}

    public Days getDay() {
        return day;
    }

    public String getName() {
        return name;
    }
}

I am using Jackson 2.9, and this answer indicates that using @JsonProperty should be enough, however I struggle to deserialize this:

public static void main(String[] args) throws JsonProcessingException {
    ObjectMapper objectMapper = new ObjectMapper();
    Event event = new Event(Days.MONDAY, "Birthday");

    String serialisedEvent = objectMapper.writeValueAsString(event);
    System.out.println(serialisedEvent);
    // {"day":"Monday","name":"Birthday"}

    Event deserialisedEvent = objectMapper.convertValue(serialisedEvent, Event.class);
    // Exception in thread "main" java.lang.IllegalArgumentException: Cannot construct instance of `xyz.blabla.Event` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"day":"Monday","name":"Birthday"}')
    // at [Source: UNKNOWN; line: -1, column: -1]
    // at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3750)
    System.out.println(deserialisedEvent.getDay());
}

I am using Java 11 and Jackson 2.9 in a Spring Boot 2 project. How can I make this work?


Solution

  • Jackson deserialization method is called readValue.

    The purpose of convertValue is different — it serializes an object (which may be a string — it would become a JSON-string-literal then) first, and then deserializes the result into an object of the target type.

    The following should work:

    Event deserialisedEvent = objectMapper.readValue(serialisedEvent, Event.class);