Reputation: 1244
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
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
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
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