Chcę serializować i deserializować niezmienny obiekt przy użyciu com.fasterxml.jackson.databind.ObjectMapper.
Niezmienna klasa wygląda następująco (tylko 3 atrybuty wewnętrzne, metody pobierające i konstruktory):
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;
}
}
Jednak kiedy uruchamiam ten test jednostkowy:
@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);
}
Mam ten wyjątek:
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
Ten wyjątek prosi mnie o utworzenie domyślnego konstruktora, ale jest to niezmienny obiekt, więc nie chcę go mieć. Jak ustawi wewnętrzne atrybuty? Całkowicie zmyliłoby to użytkownika API.
Moje pytanie brzmi: czy mogę w jakiś sposób de / serializować niezmienne obiekty bez domyślnego konstruktora?
Odpowiedzi:
Aby poinformować Jacksona, jak utworzyć obiekt do deserializacji, użyj adnotacji
@JsonCreator
i@JsonProperty
dla swoich konstruktorów, na przykład:źródło
@JsonCreator
i,@JsonProperty
ponieważ nie masz dostępu do POJO, aby go zmienić? Czy nadal istnieje sposób na deserializację obiektu?Możesz użyć prywatnego konstruktora domyślnego, a Jackson wypełni pola za pomocą refleksji, nawet jeśli są one ostateczne.
EDYCJA: I użyj domyślnego konstruktora chronionego / chronionego pakietem dla klas nadrzędnych, jeśli masz dziedziczenie.
źródło
Pierwsza odpowiedź Siergieja Petunina jest słuszna. Możemy jednak uprościć kod, usuwając nadmiarowe adnotacje @JsonProperty na każdym parametrze konstruktora.
Można to zrobić, dodając com.fasterxml.jackson.module.paramnames.ParameterNamesModule do ObjectMapper:
(Btw: ten moduł jest domyślnie zarejestrowany w SpringBoot. Jeśli używasz beana ObjectMapper z JacksonObjectMapperConfiguration lub jeśli tworzysz własny ObjectMapper z fasolą Jackson2ObjectMapperBuilder, możesz pominąć ręczną rejestrację modułu)
Na przykład:
i ObjectMapper deserializuje ten plik json bez żadnych błędów:
źródło