Я обновляюсь с 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, в частности, кажется единственным классом, который терпит неудачу сериализовать. Итак, у меня два основных вопроса:
Я также столкнулся с подобной проблемой, если вы нашли ответ, не могли бы вы предоставить его? Я разместил свой вопрос: stackoverflow.com/q/72089765/7584240, если у вас есть возможность, не могли бы вы взглянуть и дать несколько предложений?
Короткий ответ заключается в том, что Джексон в основном нарушил это поведение с помощью этого коммита: 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!
Также стоит отметить, что
mapper.canSerialize(IllegalFieldValueException.class)
возвращаетсяtrue