Je souhaite sérialiser et désérialiser un objet immuable à l'aide de com.fasterxml.jackson.databind.ObjectMapper.
La classe immuable ressemble à ceci (seulement 3 attributs internes, getters et constructeurs):
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;
}
}
Cependant, lorsque j'exécute ce test unitaire:
@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);
}
J'obtiens cette exception:
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
Cette exception me demande de créer un constructeur par défaut, mais c'est un objet immuable, donc je ne veux pas l'avoir. Comment définirait-il les attributs internes? Cela dérouterait totalement l'utilisateur de l'API.
Ma question est donc la suivante: puis-je en quelque sorte dés / sérialiser des objets immuables sans constructeur par défaut?
Réponses:
Pour que Jackson sache comment créer un objet pour la désérialisation, utilisez les annotations
@JsonCreator
et@JsonProperty
pour vos constructeurs, comme ceci:la source
@JsonCreator
et@JsonProperty
parce que vous n'avez pas accès au POJO pour le modifier? Existe-t-il encore un moyen de désérialiser l'objet?Vous pouvez utiliser un constructeur par défaut privé, Jackson remplira alors les champs via la réflexion même s'ils sont finaux privés.
EDIT: Et utilisez un constructeur par défaut protégé / package-protected pour les classes parentes si vous avez l'héritage.
la source
La première réponse de Sergei Petunin est juste. Cependant, nous pourrions simplifier le code en supprimant les annotations @JsonProperty redondantes sur chaque paramètre du constructeur.
Cela peut être fait en ajoutant com.fasterxml.jackson.module.paramnames.ParameterNamesModule dans ObjectMapper:
(Btw: ce module est enregistré par défaut dans SpringBoot. Si vous utilisez le bean ObjectMapper de JacksonObjectMapperConfiguration ou si vous créez votre propre ObjectMapper avec le bean Jackson2ObjectMapperBuilder, vous pouvez ignorer l'enregistrement manuel du module)
Par exemple:
et ObjectMapper désérialise ce json sans aucune erreur:
la source