Michael
Michael

Reputation: 591

How to deserialize JSON data from an IEX Cloud batch endpoint

I am requesting data from an IEX Cloud batch endpoint. The request contains a query string with multiple symbols and returns relevant market data. To make the question simpler, I show only a subset of the response below. I also used https://www.jsonschema2pojo.org/ to build my POJOs automatically and show this below the request. My request contains a batch of symbols for AAPL and FB in the example, but it can contain any number of user-selected symbols in production. Given how the response is structured, how can I create a generic symbol POJO? As you can see below, JSONSchema creates a POJO for each symbol (e.g. an Aapl POJO and FB POJO), but I won't always know what symbol or how many of them are requested.

IEX Cloud Response from Batch Symbol request.

{
    "AAPL": {
        "quote": {
            "symbol": "AAPL",
            "latestPrice": 133.985
        }
    },
    "FB": {
        "quote": {
            "symbol": "FB",
            "latestPrice": 339.13
        }
    }
}

POJOs built by JSONSchema.org.

-----------------------------------com.example.Aapl.java-----------------------------------

package com.example;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"quote"
})
@Generated("jsonschema2pojo")
public class Aapl {

@JsonProperty("quote")
public Quote quote;

}
-----------------------------------com.example.Fb.java-----------------------------------

package com.example;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"quote"
})
@Generated("jsonschema2pojo")
public class Fb {

@JsonProperty("quote")
public Quote__1 quote;

}
-----------------------------------com.example.Quote.java-----------------------------------

package com.example;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"symbol",
"latestPrice"
})
@Generated("jsonschema2pojo")
public class Quote {

@JsonProperty("symbol")
public String symbol;
@JsonProperty("latestPrice")
public Double latestPrice;

}
-----------------------------------com.example.Quote__1.java-----------------------------------

package com.example;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"symbol",
"latestPrice"
})
@Generated("jsonschema2pojo")
public class Quote__1 {

@JsonProperty("symbol")
public String symbol;
@JsonProperty("latestPrice")
public Double latestPrice;

}
-----------------------------------com.example.Security.java-----------------------------------

package com.example;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"AAPL",
"FB"
})
@Generated("jsonschema2pojo")
public class Security {

@JsonProperty("AAPL")
public Aapl aapl;
@JsonProperty("FB")
public Fb fb;

}

Upvotes: 0

Views: 177

Answers (1)

Andreas
Andreas

Reputation: 159260

"AAPL" and "FB" are dynamic field names, so you can't use fixed-name fields of a class to map them, but should instead use a Map<String, ...> field in the root object.

The values of "AAPL" and "FB" are the same structure, i.e. an object with a field named quote, so you need a class matching that.

The value of quote is an object with two fields named symbol and latestPrice, so you need a class matching that.

class Root {
    private Map<String, Stock> stocks = new LinkedHashMap<>();

    @JsonAnyGetter
    public Map<String, Stock> getStocks() {
        return this.stocks;
    }

    @JsonAnySetter
    public void addStock(String name, Stock value) {
        this.stocks.put(name, value);
    }
}
class Stock {
    private Quote quote;

    public Quote getQuote() {
        return this.quote;
    }

    public void setQuote(Quote quote) {
        this.quote = quote;
    }
}
class Quote {
    private String symbol;
    private BigDecimal latestPrice;

    public String getSymbol() {
        return this.symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public BigDecimal getLatestPrice() {
        return this.latestPrice;
    }

    public void setLatestPrice(BigDecimal latestPrice) {
        this.latestPrice = latestPrice;
    }
}

Upvotes: 1

Related Questions