Сбой сериализации Джексона при обновлении с версии 2.10 (InvalidDefinitionException: обработка идентификатора типа не реализована для типа java.lang.Object)

Я обновляюсь с Jackson 2.10 до 2.12, и вдруг этот простой тест (который раньше работал нормально) теперь терпит неудачу:

ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
mapper.valueToTree(new org.joda.time.IllegalFieldValueException("testName", "testValue")); // causes error
java.lang.IllegalArgumentException: Type id handling not implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer)
    at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3312)
    at com.amazon.ets.util.exception.ExceptionSerializationTest.shouldSerializeException(ExceptionSerializationTest.java:77)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer)
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.JsonSerializer.serializeWithType(JsonSerializer.java:160)
    at com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer.serialize(TypeWrappedSerializer.java:32)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3126)
    at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3307)
    ... 24 more

Из других подобных сообщений, таких как Вот этот и Вот этот, я понял, что Джексон может бороться с полиморфными типами десериализация, но это ошибка сериализация, а не десериализация. Кроме того, когда я просто пытаюсь создать свой собственный подкласс Exception и пытаюсь его сериализовать, он отлично работает. Я пытаюсь использовать это как сериализатор общего назначения, поэтому я не хочу вручную добавлять пользовательские сериализаторы для каждого типа объекта - я даже не знаю, почему IllegalFieldValueException, в частности, кажется единственным классом, который терпит неудачу сериализовать. Итак, у меня два основных вопроса:

  1. Почему это внезапно выходит из строя, когда я обновляюсь с Jackson 2.10 до более поздней версии? больше я ничего не менял! Есть ли параметр конфигурации, который я могу использовать, чтобы воспроизвести поведение предыдущей версии?
  2. Почему IllegalFieldValueException — единственный тип, который не может сериализоваться? Когда я пытаюсь сериализовать другие подклассы исключений или полиморфные типы, я не вижу этой ошибки. Что такого особенного в этом конкретном классе? (И есть ли другие классы, которые могут вызывать такое же поведение?)

Также стоит отметить, что mapper.canSerialize(IllegalFieldValueException.class) возвращается true

Dasmowenator 03.05.2022 01:58

Я также столкнулся с подобной проблемой, если вы нашли ответ, не могли бы вы предоставить его? Я разместил свой вопрос: stackoverflow.com/q/72089765/7584240, если у вас есть возможность, не могли бы вы взглянуть и дать несколько предложений?

BATMAN_2008 03.05.2022 11:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Короткий ответ заключается в том, что Джексон в основном нарушил это поведение с помощью этого коммита: https://github.com/FasterXML/jackson-databind/commit/85c9c8544f0c4f01e88241acc1573746df4f755d.

По иронии судьбы, на самом деле здесь есть комментарий от одного из разработчиков (тату), который спрашивает, должны ли они добавить параметр переопределения, разрешающий принудительную сериализацию POJO: https://github.com/FasterXML/jackson-databind/blob/2.14/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java#L891

К сожалению, этот комментарий от tatu, по-видимому, был проигнорирован, потому что нет возможности переопределить или отключить эту проверку. Даже в последней версии Джексона у него такое же плохое поведение.

Хорошая новость заключается в том, что, как вы можете видеть в реализации метода проверитьНеподдерживаемыйТип(), он выдает эту ошибку только при попытке сериализации классов в пакетах java.time или org.joda.time. Это означает, что вам не нужно беспокоиться о возникновении этого исключения при попытке сериализовать что-либо еще. Плохая новость заключается в том, что даже если вы добавите ЙодаМодуль в свой преобразователь Jackson, JodaModule на самом деле не включает типы исключений, поэтому вы все равно получите ту же ошибку.

В долгосрочной перспективе идеальным решением для Джексона было бы добавить настраиваемую опцию сериализации, чтобы принудительно сериализовать POJO для типов, связанных со временем, и/или обновить JodaModule для включения типов исключений. Но пока вы можете исправить это поведение, создав подкласс BeanSerializerFactory:

public class CustomBeanSerializerFactory extends BeanSerializerFactory {
    public CustomBeanSerializerFactory(SerializerFactoryConfig config) {
        super(config);
    }
    @Override
    protected JsonSerializer<?> _findUnsupportedTypeSerializer(SerializerProvider ctxt, JavaType type, BeanDescription beanDesc) throws JsonMappingException {
        return null;
    }
    @Override
    public SerializerFactory withConfig(SerializerFactoryConfig config) {
        if (_factoryConfig == config) return this;
        return new CustomBeanSerializerFactory(config);
    }
}

Затем настройте ObjectMapper на использование этой фабрики:

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializerFactory(new CustomBeanSerializerFactory(null));
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
mapper.valueToTree(new org.joda.time.IllegalFieldValueException("testName", "testValue")); // no error anymore - yay!

Другие вопросы по теме