2016-05-03 79 views
38

比方說,我正在向具有以下JSON的產品響應的API調用:如何使用Jackson註釋將嵌套值映射到屬性?

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

我能夠映射的產品ID和名稱就好用傑克遜註釋:

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; 
    } 
} 

然後用fromJson方法來創建產品:

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

但是現在我想弄清楚如何抓住這個品牌名稱,它是一個嵌套屬性。我希望這樣的事情會起作用:

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

但當然它沒有。有沒有簡單的方法來完成我想要使用註釋?

我試圖解析的實際JSON響應非常複雜,我不想爲每個子節點創建一個全新的類,即使我只需要一個字段。

+0

我結束了使用https://github.com/json-path/JsonPath - Spring也在底層使用它。例如,在他們的org.springframework.data.web中。 – dehumanizer

回答

36

可以這樣實現這一點:

String brandName; 

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

三層深度如何? –

+1

@Robin這不行嗎? ();());}();());}}。 ''' –

+0

這對我有效!優秀!謝謝! – Paul

-1

嗨,這裏是完整的工作代碼。

// JUnit測試類

公共類SOF {的JUnit

@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.log測試用例

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 

完全要點:https://gist.github.com/jeorfevre/7c94d4b36a809d4acf2f188f204a8058

+1

我試圖映射的實際JSON響應非常複雜。它有很多節點和子節點,並且爲每個節點創建一個類會非常痛苦,在大多數情況下,我只需要一組三重嵌套節點中的單個字段。難道沒有辦法讓單個領域不需要創建大量新課程? – kenske

+0

打開一張新的軟票並與我分享,我可以幫助你。請分享您想要映射的json結構。 :) – jeorfevre

1

爲了簡單起見,我寫了代碼......大部分內容都是自我解釋的。

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]] 
+1

這有效,但我試圖找到一種解決方案,即使我只需要一個字段,我也不必爲每個節點創建新類。 – kenske

-1

這是我如何處理這個問題:

Brand類:

package org.answer.entity; 

public class Brand { 

    private Long id; 

    private String name; 

    public Brand() { 

    } 

    //accessors and mutators 
} 

Product類:

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 
} 

這裏,brand實例將在serializationdeserialization期間被Jackson忽略,因爲它注有@JsonIgnore

Jackson將使用註解爲@JsonGetter的方法將serialization的java對象轉換爲JSON格式。所以,brandName設置爲brand.getName()

同樣,Jackson將使用@JsonSetter註釋的方法爲deserializationJSON格式轉換爲java對象。在這種情況下,您必須自己實例化brand對象並將其name屬性設置爲brandName

如果您希望它被持久性提供程序忽略,則可以使用@Transient持久性註釋和brandName

相關問題