Джексон: Сериализовать и десериализовать значения enum как целые числа

Рассмотрим следующее перечисление и класс:

public enum State {
    ON,
    OFF,
    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, OFF);
    ObjectMapper mapper = new ObjectMapper();
    String machineAsJsonString = mapper.writeValueAsString(m);
    System.out.println(machineAsJsonString);
}

В настоящее время вывод этого основного файла:

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

Этот вывод не подходит для меня, так как вместо строки "OFF" для state я хотел бы, чтобы это было 1, которое является порядковым значением OFF в перечислении state.

Итак, фактический результат, который я хочу получить, это:

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

Есть ли элегантный способ заставить его вести себя таким образом?

Ответ 1

Он должен работать, указав JsonValue mapper.

public enum State {
    ON,
    OFF,
    UNKNOWN;

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

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

ПРИМЕЧАНИЕ. При использовании для перечислений Java одна дополнительная функция - это значение возвращаемый аннотированным методом, также считается значением десериализуем, а не только строку JSON для сериализации как. Это возможно, поскольку множество значений Enum является постоянным, и можно определить отображение, но не может быть сделано вообще для типов POJO; в виде такой, это не используется для десериализации POJO

Ответ 3

Если вы хотите напечатать порядковый номер перечисления, вы можете изменить свой конструктор, чтобы принять int вместо State, а затем в своем обращении к Machine вы можете его структурировать следующим образом:

Machine m = new Machine("Machine 1", 8, State.OFF.ordinal());

Это получит порядковое значение enum переданного состояния и напечатает следующие

{name='Machine 1', numCores=8, state=1}

Ответ 4

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

public class StateSerializer extends JsonSerializer<State> {  
    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(){...}
}

Ответ 5

Еще один способ:

public enum State {

    @JsonProperty("0")
    ON,

    @JsonProperty("1")
    OFF,

    @JsonProperty("2")
    UNKNOWN
}

Тем не менее, это будет производить {"state": "1"} вместо {"state": 1} (строка, а не число). В большинстве случаев это нормально

Ответ 6

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

import com.fasterxml.jackson.annotation.JsonFormat;

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