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

Time:03-22

I would like create a Java object which map this JSON object:

{
  "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"
}

Only the "GBP" property name is dynamic field, it could be another currency symbol next time like "USD", "JPY" etc.

I create the Java class like this:


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

}

But when compile, it seems have problem. it can't map the JSON object with the dynamic field . Does anyone know how to fix it? Thanks you very much.

CodePudding user response:

You can use @JsonAnyGetter and get the additional dynamic key value pair(s) in a Map. Please refer to the usage of @JsonAnyGetter in the following example and do let me know if you still need help.

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

CodePudding user response:

May be you were thinking too complicated here. In your CurrencyConvertDto class, instead of using

@JsonProperty("rates")
private Rates rates;

you can simply use

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

(and of course adjust the getRatesand setRates methods accordingly). And then you don't need the Rates class anymore.

Jackson can cope with this out-of-the-box, even if you might have more rates in the future, like in:

{
  "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"
}

And by the way: You don't need to repeat the @JsonProperty annotations on the getter and setter methods. Putting @JsonProperty only on the member variables is already enough.

CodePudding user response:

If you are able, the simplest option would be to use a reasonable JSON design.

Here is an example:

{
  "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"
}
  • Related