Jackson: Сериализация и десериализация значений enum в виде целых чисел
Я создаю приложение на 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 ответ(ов)
Это должно работать, если указать маппер JsonValue
.
public enum State {
OFF,
ON,
UNKNOWN;
@JsonValue
public int toValue() {
return ordinal();
}
}
Это также работает для десериализации, как указано в Javadoc аннотации @JsonValue
:
ЗАМЕТКА: при использовании для перечислений Java, существует дополнительная возможность, что значение, возвращаемое аннотированным методом, также рассматривается как значение для десериализации, а не только как JSON-строка для сериализации. Это возможно, поскольку набор значений перечисления является постоянным и можно определить сопоставление. Однако это невозможно сделать в общем случае для POJO типов; поэтому это не применяется для десериализации POJO.
Вы можете использовать настройку
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/.
Вы можете сделать это следующим образом:
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).
Другой способ:
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}
.
Для завершения обсуждения, представляю еще один способ: создание пользовательского сериализатора.
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
.
Jackson с JSON: Неузнанное поле, не помеченное как проигнорируемое
Игнорирование новых полей в JSON-объектах с помощью Jackson
Сравнение членов enum в Java: использовать == или equals()?
Как преобразовать jsonString в JSONObject в Java?
Являются ли имена перечислений (enum) в Java интернированными?