Introdução à desserialização personalizada em Jackson
1. Visão geral
Este tutorial rápido ilustrará como usar Jackson 2 para desserializar JSON usando umcustom Deserializer.
Se você quiser se aprofundar e aprenderother cool things you can do with the Jackson 2, vá parathe main Jackson tutorial.
2. Desserialização Padrão
Vamos começar definindo 2 entidades e ver como Jackson desserializará uma representação JSON para essas entidades sem qualquer personalização:
public class User {
public int id;
public String name;
}
public class Item {
public int id;
public String itemName;
public User owner;
}
Agora, vamos definir a representação JSON que queremos desserializar:
{
"id": 1,
"itemName": "theItem",
"owner": {
"id": 2,
"name": "theUser"
}
}
E, finalmente, vamos desempacotar este JSON para entidades Java:
Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);
3. Deserializador personalizado emObjectMapper
No exemplo anterior, a representação JSON correspondia perfeitamente às entidades java - a seguir, simplificaremos o JSON:
{
"id": 1,
"itemName": "theItem",
"createdBy": 2
}
Ao desarmar isso exatamente para as mesmas entidades - por padrão, isso obviamente falhará:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "createdBy" (class org.example.jackson.dtos.Item),
not marked as ignorable (3 known properties: "id", "owner", "itemName"])
at [Source: [email protected]; line: 1, column: 43]
(through reference chain: org.example.jackson.dtos.Item["createdBy"])
Vamos resolver isso fazendoour own deserialization with a custom Deserializer:
public class ItemDeserializer extends StdDeserializer- {
public ItemDeserializer() {
this(null);
}
public ItemDeserializer(Class> vc) {
super(vc);
}
@Override
public Item deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
int id = (Integer) ((IntNode) node.get("id")).numberValue();
String itemName = node.get("itemName").asText();
int userId = (Integer) ((IntNode) node.get("createdBy")).numberValue();
return new Item(id, itemName, new User(userId, null));
}
}
Como você pode ver, o desserializador está trabalhando com a representação Jackson padrão de JSON - oJsonNode. Uma vez que o JSON de entrada é representado comoJsonNode, agora podemosextract the relevant information from ite construir nossa própria entidadeItem.
Simplificando, precisamosregister this custom deserializere simplesmente desserializar o JSON normalmente:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Item.class, new ItemDeserializer());
mapper.registerModule(module);
Item readValue = mapper.readValue(json, Item.class);
4. Deserializador personalizado na classe
Alternativamente, também podemosregister the deserializer directly on the class:
@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
...
}
Com o desserializador definido no nível da classe, não há necessidade de registrá-lo noObjectMapper - um mapeador padrão funcionará bem:
Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);
Este tipo de configuração por classe é muito útil em situações nas quais não podemos ter acesso direto aosObjectMapper brutos para configurar.
5. Conclusão
Este artigo mostra como alavancar Jackson 2 pararead non-standard JSON input - e como mapear essa entrada para qualquer gráfico de entidade java com controle total sobre o mapeamento.
A implementação de todos esses exemplos e fragmentos de códigocan be found in my github project - este é um projeto baseado no Eclipse, portanto, deve ser fácil de importar e executar como está.