Yanick Nedderhoff
Yanick Nedderhoff

Reputation: 1244

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?

Upvotes: 2

Views: 8103

Answers (3)

Karl
Karl

Reputation: 13

To add to this answer, I scoured the internet looking for how to add ONE-TIME as an enum value (and have it saved with the dash). Note: enums do not allow for a dash. I fixed this by simply adding

@JsonProperty("ONE-TIME")

above the enum field declaration.

Upvotes: 0

davidxxx
davidxxx

Reputation: 131496

You don't have default constructor but an arg constructor.

You have to annotate it with @JsonCreator in order that Jackson uses it to deserialize the JSON :

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

To serialize a Java object to JSON, the constructor is not used by Jackson since it doesn't create java instances but just use getters to retrieve properties of it. So it worked. But to unserialize JSON to Java object, Jackson needs to instantiate the target class. By default it looks for the no arg constructor.

Note also that annotating the constructor parameters with @JsonProperty("...") is not needed if you use the ParameterNamesModule such as :

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new ParameterNamesModule());

Spring Boot 2 provides it for you as you depends on Jackson.
Here you need it because you don't use the Mapper wiring by Spring Boot but you instantiate it by yourself.

As well as the @JsonProperty annotations located in the enum are not needed either :

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

It allows to change the serialization output of the enum but actually you don't need to change it as you map it to the day field value currently used for the enum Jackson mapping...

Upvotes: 0

Alex Shesterov
Alex Shesterov

Reputation: 27585

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);

Upvotes: 4

Related Questions