如何使用Jackson注释将嵌套值映射到属性?

ken*_*ske 75 java json jackson

假设我正在调用一个API,它响应产品的以下JSON:

{
  "id": 123,
  "name": "The Best Product",
  "brand": {
     "id": 234,
     "name": "ACME Products"
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以使用Jackson注释来映射产品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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用fromJson方法创建产品:

  JsonNode apiResponse = api.getResponse();
  Product product = Json.fromJson(apiResponse, Product.class);
Run Code Online (Sandbox Code Playgroud)

但现在我想弄清楚如何获取品牌名称,这是一个嵌套的属性.我希望这样的东西能起作用:

    @JsonProperty("brand.name")
    public String getBrandName() {
        return brandName;
    }
Run Code Online (Sandbox Code Playgroud)

但当然没有.有没有一种简单的方法可以使用注释来实现我想要的东西?

我试图解析的实际JSON响应非常复杂,我不想为每个子节点创建一个完整的新类,即使我只需要一个字段.

小智 77

你可以这样做:

String brandName;

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

  • 深层三层怎么样? (15认同)
  • 此解决方案不适用于不可变对象或“记录”。 (4认同)
  • @Robin那不行吗?```this.abbreviation =((Map <String,Object>)portalCharacteristics.get("icon")).get("ticker").toString(); ``` (3认同)
  • 对于三个级别,直接使用 JsonNode。地图变得太麻烦:`void unpackName(JsonNode company) { name = company.get("division").get("brand").get("name).asText(); }` (2认同)

小智 7

这就是我处理此问题的方式:

Brand 类:

package org.answer.entity;

public class Brand {

    private Long id;

    private String name;

    public Brand() {

    }

    //accessors and mutators
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

在此,brand实例将Jacksonserialization和中被忽略deserialization,因为该实例用注释@JsonIgnore

Jackson将使用java对象的@JsonGetterfor 注释方法serialization转换为JSON格式。因此,用brandName设置brand.getName()

同样地,Jackson将使用与注释的方法@JsonSetterdeserializationJSON格式转换成Java对象。在这种情况下,您将必须自己实例化该brand对象并name从中设置其属性brandName

您可以使用@Transient持久性与注释brandName,如果你想让它通过持久性提供被忽略。


gog*_*tad 6

您可以使用 JsonPath 表达式来映射嵌套属性。我认为没有任何官方支持(请参阅问题),但这里有一个非官方实现:https : //github.com/elasticpath/json-unmarshaller


Tos*_*far 5

最好是使用 setter 方法:

JSON:

...
 "coordinates": {
               "lat": 34.018721,
               "lng": -118.489090
             }
...
Run Code Online (Sandbox Code Playgroud)

lat 或 lng 的 setter 方法如下所示:

 @JsonProperty("coordinates")
    public void setLng(Map<String, String> coordinates) {
        this.lng = (Float.parseFloat(coordinates.get("lng")));
 }
Run Code Online (Sandbox Code Playgroud)

如果您需要阅读两者(就像通常所做的那样),那么使用自定义方法

@JsonProperty("coordinates")
public void setLatLng(Map<String, String> coordinates){
    this.lat = (Float.parseFloat(coordinates.get("lat")));
    this.lng = (Float.parseFloat(coordinates.get("lng")));
}
Run Code Online (Sandbox Code Playgroud)