Десериализовать поле enum с Джексоном - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть простое перечисление 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, и этот ответ указывает на то, что использования @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());
}

Я использую Java 11 и Jackson 2.9 в проекте Spring Boot 2.Как я могу сделать эту работу?

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Метод десериализации Джексона называется readValue.

Цель convertValue отличается - он сериализует объект (который может быть строкой - он станет JSON-затем строка-литерал), а затем десериализует результат в объект целевого типа.

Должно работать следующее:

Event deserialisedEvent = objectMapper.readValue(serialisedEvent, Event.class);
0 голосов
/ 03 февраля 2019

У вас нет конструктора по умолчанию, но есть конструктор arg.

Вы должны аннотировать его с помощью @JsonCreator, чтобы Джексон использовал его для десериализации JSON:

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

Чтобы сериализовать объект Java в JSON, Джексон не использует конструкторпоскольку он не создает экземпляры Java, а просто использует методы получения для получения его свойств.Так это сработало.Но чтобы десериализовать JSON в объект Java, Джексону нужно создать экземпляр целевого класса.По умолчанию он ищет конструктор без аргументов.

Обратите внимание, что аннотирование параметров конструктора с помощью @JsonProperty("...") не требуется, если вы используете ParameterNamesModule, например:

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

Spring Boot 2 обеспечивает этодля вас, поскольку вы зависите от Джексона.
Здесь вам это нужно, потому что вы не используете проводку Mapper от Spring Boot, а создаете ее сами.

А также аннотации @JsonProperty, расположенные вперечисление также не требуется:

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

Это позволяет изменить вывод сериализации перечисления, но на самом деле вам не нужно изменять его, поскольку вы сопоставляете его со значением поля day, используемым в настоящее время дляперечисление Джексона ...

...