如何使用 JSON 中的动态字段将 JSON 映射到 Java POJO?

How to map JSON to Java POJO with a dynamic field in JSON?

我想创建一个映射此 JSON 对象的 Java 对象:

{
  "base_currency_code": "HKD",
  "base_currency_name": "Hong Kong dollar",
  "amount": "150.5800",
  "updated_date": "2022-03-20",
  "rates": {
    "GBP": {
      "currency_name": "Pound sterling",
      "rate": "0.0975",
      "rate_for_amount": "14.6774"
    }
  },
  "status": "success"
}

只有"GBP" 属性名称是动态字段,下次可能是其他货币符号,如"USD""JPY"

我这样创建 Java class:


@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
    "base_currency_code",
    "base_currency_name",
    "amount",
    "updated_date",
    "rates",
    "status"
})
public class CurrencyConvertDto {

    @JsonProperty("base_currency_code")
    private String baseCurrencyCode;
    @JsonProperty("base_currency_name")
    private String baseCurrencyName;
    @JsonProperty("amount")
    private String amount;
    @JsonProperty("updated_date")
    private String updatedDate;
    @JsonProperty("rates")
    private Rates rates;
    @JsonProperty("status")
    private String status;
    /*
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    */

    @JsonProperty("base_currency_code")
    public String getBaseCurrencyCode() {
        return baseCurrencyCode;
    }

    @JsonProperty("base_currency_code")
    public void setBaseCurrencyCode(String baseCurrencyCode) {
        this.baseCurrencyCode = baseCurrencyCode;
    }

    @JsonProperty("base_currency_name")
    public String getBaseCurrencyName() {
        return baseCurrencyName;
    }

    @JsonProperty("base_currency_name")
    public void setBaseCurrencyName(String baseCurrencyName) {
        this.baseCurrencyName = baseCurrencyName;
    }

    @JsonProperty("amount")
    public String getAmount() {
        return amount;
    }

    @JsonProperty("amount")
    public void setAmount(String amount) {
        this.amount = amount;
    }

    @JsonProperty("updated_date")
    public String getUpdatedDate() {
        return updatedDate;
    }

    @JsonProperty("updated_date")
    public void setUpdatedDate(String updatedDate) {
        this.updatedDate = updatedDate;
    }

    @JsonProperty("rates")
    public Rates getRates() {
        return rates;
    }

    @JsonProperty("rates")
    public void setRates(Rates rates) {
        this.rates = rates;
    }

    @JsonProperty("status")
    public String getStatus() {
        return status;
    }

    @JsonProperty("status")
    public void setStatus(String status) {
        this.status = status;
    }

}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Rates {

    private List<Map<String, String>> rateInfo = new ArrayList<Map<String, String>>();

    @JsonAnySetter
    public void setDynamicProperty(String name, Map<String, String> map) {
        rateInfo.add(map);
    }

    public List<Map<String, String>> getRateInfo() {
        return rateInfo;
    }

    public void setRateInfo(List<Map<String, String>> rateInfo) {
        this.rateInfo = rateInfo;
    }

}


@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
    "currency_name",
    "rate",
    "rate_for_amount"
})
public class RateInfo {

    @JsonProperty("currency_name")
    private String currencyName;
    @JsonProperty("rate")
    private String rate;
    @JsonProperty("rate_for_amount")
    private String rateForAmount;
    /*
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    */

    @JsonProperty("currency_name")
    public String getCurrencyName() {
        return currencyName;
    }

    @JsonProperty("currency_name")
    public void setCurrencyName(String currencyName) {
        this.currencyName = currencyName;
    }

    @JsonProperty("rate")
    public String getRate() {
        return rate;
    }

    @JsonProperty("rate")
    public void setRate(String rate) {
        this.rate = rate;
    }

    @JsonProperty("rate_for_amount")
    public String getRateForAmount() {
        return rateForAmount;
    }

    @JsonProperty("rate_for_amount")
    public void setRateForAmount(String rateForAmount) {
        this.rateForAmount = rateForAmount;
    }

}

但是编译的时候好像有问题。它无法将 JSON 对象映射到动态字段。有谁知道如何修理它?非常感谢。

您可以使用@JsonAnyGetter 并在地图中获取额外的动态键值对。请参考以下示例中@JsonAnyGetter 的用法,如果您还需要帮助,请告诉我。

https://www.logicbig.com/tutorials/misc/jackson/jackson-any-setter.html

可能是你想的太复杂了。 在您的 CurrencyConvertDto class 中,而不是使用

@JsonProperty("rates")
private Rates rates;

你可以简单地使用

@JsonProperty("rates")
private Map<String, RateInfo> rates;

(当然还要相应地调整 getRatessetRates 方法)。 然后你就不需要 Rates class 了。

杰克逊可以应对out-of-the-box。 它将处理任意货币代码作为地图的键,如:

{
  "base_currency_code": "HKD",
  "base_currency_name": "Hong Kong dollar",
  "amount": "150.5800",
  "updated_date": "2022-03-20",
  "rates": {
    "GBP": {
      "currency_name": "Pound sterling",
      "rate": "0.0975",
      "rate_for_amount": "14.6774"
    },
    "EUR": {
      "currency_name": "Euro",
      "rate": "0.120",
      "rate_for_amount": "18.07"
    }
  },
  "status": "success"
}

顺便说一下:您不需要重复 @JsonProperty getter 和 setter 方法的注解。放 @JsonProperty 仅在成员变量上已经足够了。

如果可以的话, 最简单的选择是使用合理的 JSON 设计。

这是一个例子:

{
  "base_currency_code": "HKD",
  "base_currency_name": "Hong Kong dollar",
  "amount": "150.5800",
  "updated_date": "2022-03-20",
  "rates": {
    "currentySymbol": "GBP",
    "currency_name": "Pound sterling",
    "rate": "0.0975",
    "rate_for_amount": "14.6774"
    }
  },
  "status": "success"
}