132 votes

Comment mapper une valeur imbriquée sur une propriété à l'aide des annotations de Jackson?

Disons que je suis en train de faire un appel à une API qui répond avec le JSON suivants pour un produit:

{
  "id": 123,
  "name": "The Best Product",
  "brand": {
     "id": 234,
     "name": "ACME Products"
  }
}

Je suis en mesure de cartographier l'id du produit et le nom de l'amende juste à l'aide de Jackson annotations:

public class ProductTest {
    private int productId;
    private String productName, brandName;

    @JsonProperty("id")
    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @JsonProperty("name")
    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }
}

Et puis, à l'aide de la fromJson méthode pour créer le produit:

  JsonNode apiResponse = api.getResponse();
  Product product = Json.fromJson(apiResponse, Product.class);

Mais maintenant, je suis à essayer de comprendre comment saisir le nom de la marque, qui est imbriqué dans celui de la propriété. J'espérais que quelque chose de ce genre:

    @JsonProperty("brand.name")
    public String getBrandName() {
        return brandName;
    }

Mais bien sûr, il n'a pas. Est-il un moyen facile d'accomplir ce que je veux à l'aide d'annotations?

La réelle réponse JSON je suis en train de l'analyser est très complexe, et je ne veux pas avoir à créer une nouvelle classe pour chaque sous-nœud, même si je n'ai besoin que d'un seul champ.

140voto

Jacek Grobelny Points 585

Vous pouvez réaliser ceci comme ça:

 String brandName;

@JsonProperty("brand")
private void unpackNameFromNestedObject(Map<String, String> brand) {
    brandName = brand.get("name");
}
 

17voto

Sunny KC Points 45

C'est la façon dont j'ai traité ce problème:

Brand classe:

package org.answer.entity;

public class Brand {

    private Long id;

    private String name;

    public Brand() {

    }

    //accessors and mutators
}

Product classe:

package org.answer.entity;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;

public class Product {

    private Long id;

    private String name;

    @JsonIgnore
    private Brand brand;

    private String brandName;

    public Product(){}

    @JsonGetter("brandName")
    protected String getBrandName() {
        if (brand != null)
            brandName = brand.getName();
        return brandName;
    }

    @JsonSetter("brandName")
    protected void setBrandName(String brandName) {
        if (brandName != null) {
            brand = new Brand();
            brand.setName(brandName);
        }
        this.brandName = brandName;
    }

//other accessors and mutators
}

Ici, l' brand instance sera ignoré par Jackson cours serialization et deserialization, car il est annotée avec l' @JsonIgnore.

Jackson va utiliser la méthode annotée avec l' @JsonGetter pour serialization d'objet java en JSON format. Ainsi, l' brandName est configuré avec l' brand.getName().

De même, Jackson va utiliser la méthode annotée avec l' @JsonSetter pour deserialization de JSON format en objet java. Dans ce scénario, vous devez instancier l' brand objet vous-même et l'ensemble de ses name de la propriété de brandName.

Vous pouvez utiliser @Transient de la persistance d'annotation avec brandName, si vous voulez qu'il soit ignoré par le fournisseur de persistance.

7voto

gogstad Points 46

Vous pouvez utiliser les expressions JsonPath pour mapper des propriétés imbriquées. Je ne pense pas qu'il y ait un support officiel (voir ce numéro), mais il y a une implémentation non officielle ici: https://github.com/elasticpath/json-unmarshaller

-6voto

Pour faire simple ..j'ai écrit le code ...plus de il est auto-explicatif.

Main Method

package com.test;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class LOGIC {

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        String DATA = "{\r\n" + 
                "  \"id\": 123,\r\n" + 
                "  \"name\": \"The Best Product\",\r\n" + 
                "  \"brand\": {\r\n" + 
                "     \"id\": 234,\r\n" + 
                "     \"name\": \"ACME Products\"\r\n" + 
                "  }\r\n" + 
                "}";

        ProductTest productTest = objectMapper.readValue(DATA, ProductTest.class);
        System.out.println(productTest.toString());

    }

}

Class ProductTest

package com.test;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ProductTest {

    private int productId;
    private String productName;
    private BrandName brandName;

    @JsonProperty("id")
    public int getProductId() {
        return productId;
    }
    public void setProductId(int productId) {
        this.productId = productId;
    }

    @JsonProperty("name")
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }

    @JsonProperty("brand")
    public BrandName getBrandName() {
        return brandName;
    }
    public void setBrandName(BrandName brandName) {
        this.brandName = brandName;
    }

    @Override
    public String toString() {
        return "ProductTest [productId=" + productId + ", productName=" + productName + ", brandName=" + brandName
                + "]";
    }



}

Class BrandName

package com.test;

public class BrandName {

    private Integer id;
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "BrandName [id=" + id + ", name=" + name + "]";
    }




}

OUTPUT

ProductTest [productId=123, productName=The Best Product, brandName=BrandName [id=234, name=ACME Products]]

-8voto

jeorfevre Points 1785

Salut voici le travail complet de code.

//DE LA CLASSE DE TEST JUNIT

public class sof {

@Test
public void test() {

    Brand b = new Brand();
    b.id=1;
    b.name="RIZZE";

    Product p = new Product();
    p.brand=b;
    p.id=12;
    p.name="bigdata";


    //mapper
    ObjectMapper o = new ObjectMapper();
    o.registerSubtypes(Brand.class);
    o.registerSubtypes(Product.class);
    o.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

    String json=null;
    try {
        json = o.writeValueAsString(p);
        assertTrue(json!=null);
        logger.info(json);

        Product p2;
        try {
            p2 = o.readValue(json, Product.class);
            assertTrue(p2!=null);
            assertTrue(p2.id== p.id);
            assertTrue(p2.name.compareTo(p.name)==0);
            assertTrue(p2.brand.id==p.brand.id);
            logger.info("SUCCESS");
        } catch (IOException e) {

            e.printStackTrace();
            fail(e.toString());
        }




    } catch (JsonProcessingException e) {

        e.printStackTrace();
        fail(e.toString());
    }


}
}




**// Product.class**
    public class Product {
    protected int id;
    protected String name;

    @JsonProperty("brand") //not necessary ... but written
    protected Brand brand;

}

    **//Brand class**
    public class Brand {
    protected int id;
    protected String name;     
}

//Console.journal des cas de test junit

2016-05-03 15:21:42 396 INFO  {"id":12,"name":"bigdata","brand":{"id":1,"name":"RIZZE"}} / MReloadDB:40 
2016-05-03 15:21:42 397 INFO  SUCCESS / MReloadDB:49 

Complet gist : https://gist.github.com/jeorfevre/7c94d4b36a809d4acf2f188f204a8058

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X