Я хочу сериализовать и десериализовать неизменяемый объект с помощью com.fasterxml.jackson.databind.ObjectMapper.
Неизменяемый класс выглядит так (всего 3 внутренних атрибута, геттеры и конструкторы):
public final class ImportResultItemImpl implements ImportResultItem {
private final ImportResultItemType resultType;
private final String message;
private final String name;
public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
super();
this.resultType = resultType;
this.message = message;
this.name = name;
}
public ImportResultItemImpl(String name, ImportResultItemType resultType) {
super();
this.resultType = resultType;
this.name = name;
this.message = null;
}
@Override
public ImportResultItemType getResultType() {
return this.resultType;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public String getName() {
return this.name;
}
}
Однако, когда я запускаю этот модульный тест:
@Test
public void testObjectMapper() throws Exception {
ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
System.out.println("serialized: " + serialized);
//this line will throw exception
ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}
Я получаю это исключение:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
at
... nothing interesting here
Это исключение просит меня создать конструктор по умолчанию, но это неизменяемый объект, поэтому я не хочу его иметь. Как бы он установил внутренние атрибуты? Это полностью запутает пользователя API.
Итак, мой вопрос: могу ли я каким-то образом де / сериализовать неизменяемые объекты без конструктора по умолчанию?
Ответы:
Для того, чтобы Джексон знает , как создать объект для десериализации, используйте
@JsonCreator
и@JsonProperty
аннотации для конструкторов, как это:источник
@JsonCreator
и@JsonProperty
аннотаций , потому что у вас нет доступа к POJO , чтобы изменить его? Есть ли еще способ десериализации объекта?Вы можете использовать частный конструктор по умолчанию, затем Джексон заполнит поля через отражение, даже если они являются закрытыми окончательными.
РЕДАКТИРОВАТЬ: И используйте защищенный / защищенный пакетом конструктор по умолчанию для родительских классов, если у вас есть наследование.
источник
Первый ответ Сергея Петунина правильный. Однако мы могли бы упростить код, удалив избыточные аннотации @JsonProperty для каждого параметра конструктора.
Это можно сделать, добавив com.fasterxml.jackson.module.paramnames.ParameterNamesModule в ObjectMapper:
(Кстати: этот модуль по умолчанию зарегистрирован в SpringBoot. Если вы используете bean-компонент ObjectMapper из JacksonObjectMapperConfiguration или если вы создаете свой собственный ObjectMapper с bean-компонентом Jackson2ObjectMapperBuilder, вы можете пропустить ручную регистрацию модуля)
Например:
и ObjectMapper десериализует этот json без ошибок:
источник