Mise à jour:
J'ai essayé de déboguer dans le code source jackson et de découvrir que dans la méthode
deserialize(JsonParser jp, DeserializationContext ctxt)
de
SettableBeanProperty.Java
quand le _valueTypeDeserializer
n'est pas nul, il n'utilisera jamais _valueDeserializer
.
Est-ce une supposition correcte que TypeDeserializer devrait être plus approprié que ValueDeserializer?
J'essaie d'utiliser @JsonDeserialize
pour définir un désérialiseur personnalisé pour un champ avec des types polymorphes. Je peux réussir à utiliser @JsonDeserialize
et @JsonTypeInfo
séparément. Mais quand je les utilise ensemble, il semble que le @JsonDeserialize
l'annotation est ignorée.
Voici ma hiérarchie de classes:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", defaultImpl = Definition.class)
@JsonSubTypes({@Type(value = Definition.class, name = "normal"),
@Type(value = FormDefinition.class, name = "form")})
public class Definition {
private String name;
private String description;
// getter&setter for name&description
}
public class FormDefinition extends Definition {
private String formName;
@JsonDeserialize(using = DefinitionDeserializer.class)
private Definition definition;
public String getFormName() {
return formName;
}
public void setFormName(String formName) {
this.formName = formName;
}
public void setDefinition(Definition definition) {
this.definition = definition;
}
}
public class DefinitionDeserializer extends JsonDeserializer<Definition> {
@Override
public Definition deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
Definition definition = new Definition();
String name = jsonParser.readValueAs(String.class);
definition.setName(name);
return definition;
}
}
public class App
{
public static void main( String[] args ) throws IOException {
String sampleData = "{\"type\":\"form\",\"definition\":\"super\",\"formName\":\"FormName\"}";
ObjectMapper mapper = new ObjectMapper();
Definition definition = mapper.readValue(sampleData, Definition.class);
System.out.println(definition);
}
}
L'exécution de l'exemple d'application principale génère une exception:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class jp.co.worksap.model.Definition] from String value ('super'); no single-String constructor/factory method (through reference chain: jp.co.worksap.model.FormDefinition["definition"])
qui semble utiliser AsPropertyTypeDeserializer
pour désérialiser le champ definition
de la classe FormDefinition
au lieu du désérialiseur annoté DefinitionDeserializer
.
Je pense que la partie délicate ici est que le champ que je veux utiliser le désérialiseur personnalisé est également de type Definition
qui utilisant @JsonTypeInfo
pour résoudre les problèmes polymorphes.
Existe-t-il un moyen de les utiliser ensemble? Merci.
Jackson traite @JsonTypeInfo
avant de choisir le désérialiseur à utiliser, probablement parce que le choix du désérialiseur peut dépendre généralement du type. Cependant, vous pouvez facilement désactiver cela sur une base par champ de la même manière que vous spécifiez le désérialiseur personnalisé - en annotant directement le champ:
@JsonDeserialize(using = DefinitionDeserializer.class)
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
private Definition definition;