0

Jackson: Сериализация и десериализация значений enum в виде целых чисел

10

Я создаю приложение на Java и у меня возникла проблема с сериализацией перечислений в формате JSON. У меня есть следующий enum и класс:

public enum State {
    OFF,
    ON,
    UNKNOWN
}

public class Machine {
    String name;
    int numCores;
    State state;

    public Machine(String name, int numCores, State state) {
        this.name = name;
        this.numCores = numCores;
        this.state = state;
    }
}

В качестве примера, вот моё главное приложение:

public static void main(String args[]) {
    Machine m = new Machine("Machine 1", 8, State.OFF);
    ObjectMapper mapper = new ObjectMapper();
    String machineAsJsonString = mapper.writeValueAsString(m);
    System.out.println(machineAsJsonString);
}

В настоящее время вывод программы выглядит так:

{"name" : "Machine 1", "numCores" : 8, "state" : "OFF"}

Но меня не устраивает этот результат, так как вместо строки "OFF" в поле state я хотел бы получить значение 0, которое соответствует порядковому номеру OFF в перечислении State.

Мне нужен вывод в таком формате:

{"name" : "Machine 1", "numCores" : 8, "state" : 0}

Существует ли элегантный способ сделать так, чтобы сериализация работала именно так?

5 ответ(ов)

0

Это должно работать, если указать маппер JsonValue.

public enum State {
    OFF,
    ON,
    UNKNOWN;

    @JsonValue
    public int toValue() {
        return ordinal();
    }
}

Это также работает для десериализации, как указано в Javadoc аннотации @JsonValue:

ЗАМЕТКА: при использовании для перечислений Java, существует дополнительная возможность, что значение, возвращаемое аннотированным методом, также рассматривается как значение для десериализации, а не только как JSON-строка для сериализации. Это возможно, поскольку набор значений перечисления является постоянным и можно определить сопоставление. Однако это невозможно сделать в общем случае для POJO типов; поэтому это не применяется для десериализации POJO.

0

Вы можете использовать настройку

objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);

Смотрите полный набор тестов по ссылке: https://github.com/FasterXML/jackson-databind/blob/master/src/test/java/com/fasterxml/jackson/databind/ser/TestEnumSerialization.java.

Спасибо за подсказку на сайте: https://righele.it/2016/01/30/jackson-deserialization-from-json-to-java-enums/.

0

Вы можете сделать это следующим образом:

import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum State {
    OFF,
    ON,
    UNKNOWN
}

Этот код использует аннотацию @JsonFormat из библиотеки Jackson для того, чтобы сериализовать ваш enum в виде чисел. Это позволяет вам получать более компактное представление при сериализации и делать данные более удобными для обработки. В данном случае значение каждого элемента перечисления будет сериализовано как его порядковый номер (OFF - 0, ON - 1, UNKNOWN - 2).

0

Другой способ:

public enum State {

    @JsonProperty("0")
    OFF,

    @JsonProperty("1")
    ON,

    @JsonProperty("2")
    UNKNOWN
}

Однако данный подход приведет к тому, что будет сгенерирован JSON вида {"state" : "1"}, а не {"state" : 1} (строка вместо числа). В большинстве случаев это приемлемо, но если вам необходимо, чтобы значение было представлено именно как число, то можно рассмотреть вариант с использованием аннотации @JsonValue, чтобы явно указать числовые представления Enum:

public enum State {

    OFF(0),
    ON(1),
    UNKNOWN(2);

    private final int value;

    State(int value) {
        this.value = value;
    }

    @JsonValue
    public int getValue() {
        return value;
    }
}

В этом случае JSON будет выглядеть как {"state": 1}.

0

Для завершения обсуждения, представляю еще один способ: создание пользовательского сериализатора.

public class StateSerializer extends JsonSerializer<State> {  
    @Override
    public void serialize(State value, JsonGenerator generator, SerializerProvider provider) 
            throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("id");
        generator.writeNumber(value.getId());
        generator.writeEndObject();
    }
}

@JsonSerialize(using = StateSerializer.class)
public enum State { 
    // Ваши значения перечисления здесь
    ...
    
    public int getId() {
        // Реализация метода
        ...
    }
}

Таким образом, вы можете создать кастомный сериализатор для вашего перечисления State, который будет формировать JSON с полем id.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь