Решение проблемы десериализации enum в Java с Jackson

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для выполнения операций сериализации и десериализации перечислений (enum) в Jackson применяются аннотации @JsonValue и @JsonCreator. Аннотация @JsonValue отмечает метод, возвращающий значение для сериализации, в то время как @JsonCreator используется для статического метода, который восстанавливает перечисление из его сериализованной формы:

Java
Скопировать код
public enum Type {
    YES("Y"), NO("N");

    private final String code;

    Type(String code) {
        this.code = code;
    }

    @JsonValue
    public String getCode() {
        return code;
    }

    @JsonCreator
    public static Type fromCode(String code) {
        return Arrays.stream(Type.values())
                     .filter(type -> type.code.equals(code))
                     .findFirst()
                     .orElseThrow(() -> new IllegalStateException("Нераспознанный код: " + code));
    }
}

Данный пример демонстрирует, что значение Type.YES будет сериализовано как "Y" и, в свою очередь, десериализовано из "Y" в Type.YES.

Кинга Идем в IT: пошаговый план для смены профессии

Регистр, проверка на ошибки и прочие особенности

При наличии нестандартных правил привязки перечислений или в случае, когда JSON не учитывает регистр, можно создать Map для регистронезависимой десериализации.

Java
Скопировать код
public static Type forValue(String code) {
    return stringToEnumMap.get(StringUtils.lowerCase(code));
}

Также стоит задуматься об обработке неожиданных значений в сериализаторе. Вы можете предусмотреть возврат null из метода toValue() или выброс исключения.

Пользовательские сериализаторы/десериализаторы: делайте по-своему!

Для более точного контроля над процессами сериализации и десериализации вы можете использовать свои собственные классы сериализаторов и десериализаторов. Это позволяет реализовывать более сложную логику и обеспечивает гибкость при работе с нестандартными формами перечислений.

Java
Скопировать код
public class MySerializer extends StdSerializer<MyEnum> {
    public MySerializer() {
        super(MyEnum.class);
    }

    @Override
    public void serialize(MyEnum value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeString(value.getCustomString());
    }
}

С версии Jackson 2.6 можно использовать аннотацию @JsonProperty для определения имени каждого значения перечисления при сериализации.

Java
Скопировать код
public enum Role {
    @JsonProperty("Admin")
    ADMINISTRATOR,
    @JsonProperty("Janitor")
    SUPER_USER
}

Крайние случаи: возвращение Enum!

При работе с перечислениями, имеющими дополнительные характеристики, или когда необходима полиморфная десериализация, настройте ваши решения таким образом, чтобы Jackson мог корректно их обработать.

Для обработки неопределённых или устаревших значений перечислений можно использовать аннотацию @JsonEnumDefaultValue.

Визуализация

Работа с сериализацией/десериализацией перечислений в Jackson напоминает работу с конструктором LEGO:

Markdown
Скопировать код
Блок (🟨 Enum)
- Блок A (🟥 Индикатор)
- Блок B (🟩 Основное содержание)
- Блок C (🟦 Завершение)

Сериализация аналогична разбиранию конструктора:

Java
Скопировать код
@JsonValue
public String toJson() {
    return name().toLowerCase(Locale.ROOT);
}

После этого 🟦 преобразуется в JSON в виде "завершение".

Десериализация — это сборка конструктора обратно:

Java
Скопировать код
@JsonCreator
public static Dish fromJson(String jsonValue) {
    return Dish.valueOf(jsonValue.toUpperCase(Locale.ROOT));
}

Таким образом, "завершение" вновь становится 🟦.

К размышлению: хорошее, плохое и ужасное

Настройка ObjectMapper

Настройте ObjectMapper, чтобы глобально управлять обработкой перечислений в вашем приложении.

Java
Скопировать код
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);

Логика десериализации

Логика десериализации должна быть готова к эффективной работе с разнообразными данными, обеспечивая таким образом надёжность всего приложения.

Правильная работа!

Убедитесь, что ваши сериализаторы/десериализаторы совместимы с используемыми версиями Java и Jackson.

Полезные материалы

  1. JsonEnumDefaultValue (Jackson-annotations 2.9.0 API)
  2. Serialization features · FasterXML/jackson-databind Wiki · GitHub
  3. JacksonPolymorphicDeserialization · FasterXML/jackson-docs Wiki · GitHub
  4. No serializer found for class org.hibernate.proxy.pojo.javassist.Javassist? – Stack Overflow
  5. Jackson Custom Serializer – Составление собственного сериализатора
  6. Jackson Custom Deserializer – Реализация собственной десериализации
  7. Jackson Advanced Polymorphic Type Handling