java - jsonserialize - jsonvalue jackson
Deserializador personalizado Jackson para un campo con tipos polimórficos (1)
Actualizar:
Intenté depurar en el código fuente de Jackson y descubrir que en el método
deserialize(JsonParser jp, DeserializationContext ctxt)
de
SettableBeanProperty.java
cuando _valueTypeDeserializer
no es nulo, nunca utilizará _valueDeserializer
.
¿Es esta una suposición correcta de que TypeDeserializer debería ser más apropiado que ValueDeserializer?
Estoy tratando de usar @JsonDeserialize
para definir deserializador personalizado para un campo con tipos polimórficos. Puedo tener éxito al usar @JsonDeserialize
y @JsonTypeInfo
separado. Pero cuando los uso juntos, parece que la anotación @JsonDeserialize
se ignora.
Aquí está mi jerarquía de clases:
1. Definition.java
@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
}
2. FormDefinition.java
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;
}
}
3. DefinitionDeserializer.java
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;
}
}
Muestra principal
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);
}
}
Ejecutar la aplicación principal de ejemplo lanzará una excepción:
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"])
que parece utilizar AsPropertyTypeDeserializer
para deserializar el campo de definition
de la clase FormDefinition
lugar del deserializador anotado DefinitionDeserializer
.
Creo que la parte difícil aquí es que el campo que deseo usar deserializador personalizado es también un tipo de Definition
que usa @JsonTypeInfo
para resolver los problemas polimórficos.
¿Hay alguna manera de usarlos juntos? Gracias.
Jackson procesa @JsonTypeInfo
antes de elegir qué Deserializer usar, probablemente porque la elección de Deserializer podría depender generalmente del tipo. Sin embargo, puede deshabilitar esto fácilmente por campo de la misma manera que especifica Deserializer personalizado, anotando el campo directamente:
@JsonDeserialize(using = DefinitionDeserializer.class)
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
private Definition definition;