Ich möchte ein unveränderliches Objekt mit com.fasterxml.jackson.databind.ObjectMapper serialisieren und deserialisieren.
Die unveränderliche Klasse sieht folgendermaßen aus (nur 3 interne Attribute, Getter und Konstruktoren):
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;
}
}
Wenn ich jedoch diesen Komponententest durchführe:
@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);
}
Ich bekomme diese Ausnahme:
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
Diese Ausnahme fordert mich auf, einen Standardkonstruktor zu erstellen, aber dies ist ein unveränderliches Objekt, daher möchte ich es nicht haben. Wie würde es die internen Attribute einstellen? Dies würde den Benutzer der API völlig verwirren.
Meine Frage lautet also: Kann ich unveränderliche Objekte ohne Standardkonstruktor irgendwie de / serialisieren?
Antworten:
Verwenden Sie die Annotationen
@JsonCreator
und@JsonProperty
für Ihre Konstruktoren wie folgt, um Jackson wissen zu lassen, wie ein Objekt für die Deserialisierung erstellt wird :quelle
@JsonCreator
und hinzufügen können,@JsonProperty
weil Sie keinen Zugriff auf das POJO haben, um es zu ändern? Gibt es noch eine Möglichkeit, das Objekt zu deserialisieren?Sie können einen privaten Standardkonstruktor verwenden. Jackson füllt die Felder dann per Reflektion aus, auch wenn sie privat final sind.
BEARBEITEN: Und verwenden Sie einen geschützten / paketgeschützten Standardkonstruktor für übergeordnete Klassen, wenn Sie Vererbung haben.
quelle
Die erste Antwort von Sergei Petunin ist richtig. Wir könnten jedoch den Code vereinfachen, indem wir redundante @ JsonProperty-Annotationen für jeden Parameter des Konstruktors entfernen.
Dies kann durch Hinzufügen von com.fasterxml.jackson.module.paramnames.ParameterNamesModule zu ObjectMapper erfolgen:
(Übrigens: Dieses Modul ist standardmäßig in SpringBoot registriert. Wenn Sie die ObjectMapper-Bean von JacksonObjectMapperConfiguration verwenden oder einen eigenen ObjectMapper mit der Bean Jackson2ObjectMapperBuilder erstellen, können Sie die manuelle Registrierung des Moduls überspringen.)
Beispielsweise:
und ObjectMapper deserialisiert diesen JSON ohne Fehler:
quelle