Introdução à desserialização personalizada em Jackson

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á.