与杰克逊反序列化枚举字段

时间:2019-02-03 13:18:50

标签: java jackson objectmapper

我有一个简单的枚举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;
    }
}

和一个类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;
    }
}

我正在使用Jackson 2.9,this answer表示使用@JsonProperty就足够了,但是我很难反序列化:

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

我在Spring Boot 2项目中使用Java 11和Jackson 2.9。我该如何工作?

3 个答案:

答案 0 :(得分:3)

杰克逊反序列化方法称为readValue

convertValue的用途有所不同-首先对对象(可能是字符串,然后将其序列化为JSON字符串)序列化,然后反序列化结果变成目标类型的对象。

以下应该可以工作:

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

答案 1 :(得分:0)

您没有默认构造函数,而是arg构造函数。

您必须用@JsonCreator进行注释,以便Jackson可以使用它反序列化JSON:

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

要将Java对象序列化为JSON,Jackson不使用该构造函数,因为它不会创建Java实例,而只是使用getter来获取其属性。这样就行了。 但是为了将JSON反序列化为Java对象,Jackson需要实例化目标类。默认情况下,它查找no arg构造函数。

还请注意,如果使用ParameterNamesModule,例如:

,则不需要用@JsonProperty("...")注释构造函数参数。
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new ParameterNamesModule());

Spring Boot 2为您提供了它,因为您依赖Jackson。
在这里,您需要它,因为您不使用Spring Boot的Mapper接线,而是自己实例化它。

也不需要枚举中的@JsonProperty批注:

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

它允许更改枚举的序列化输出,但实际上,在将其映射到当前用于枚举Jackson映射的day字段值时,您无需更改它。

答案 2 :(得分:0)

为了补充这个答案,我在互联网上搜索,寻找如何将 ONE-TIME 添加为枚举值(并将其与破折号一起保存)。注意:枚举不允许有破折号。我通过简单地添加

来解决这个问题
@JsonProperty("ONE-TIME")

在枚举字段声明之上。