Getting null values while mapping a JSON to POJO

时间:2019-02-18 00:44:42

标签: java json jackson

I am trying to map a JSON to POJO using Jackson. However, as this JSON contains a nested map of objects, when i de-serialize it to the POJO, the timeseries information is not converted to the POJO. I am only able to get the metadata part and the date part in the timeseries block. The other fields in the timeseries block such as open, high and low are always null.

It seems like Jackson is not able to match the fields with in the TimeSeries class. Can someone please tell how should I do this or point me in the correct direction. Or if there is some other better way to do this. Thanks!

Here is an example of the JSON

{
"Meta Data": {
    "1. Information": "Daily Prices (open, high, low, close) and Volumes",
    "2. Symbol": "MSFT",
    "3. Last Refreshed": "2019-02-15",
    "4. Output Size": "Compact",
    "5. Time Zone": "US/Eastern"
},
"Time Series (Daily)": {
    "2019-02-15": {
        "1. open": "107.9100",
        "2. high": "108.3000",
        "3. low": "107.3624",
        "4. close": "108.2200",
        "5. volume": "26606886"
    },
    "2019-02-14": {
        "1. open": "106.3100",
        "2. high": "107.2900",
        "3. low": "105.6600",
        "4. close": "106.9000",
        "5. volume": "21784703"
    }
 }
}

Now, in order to map this JSON, I have created these POJO's

@JsonIgnoreProperties(ignoreUnknown = true)
public class HistoricalStock {
@JsonProperty("Meta Data")
private MetaData metadata;

private Map<String, TimeSeriesInfo> stockDailyData = new HashMap<String, TimeSeriesInfo>();

public HistoricalStock() {
}

public MetaData getMetadata() {
    return metadata;
}

public void setMetadata(MetaData metadata) {
    this.metadata = metadata;
}

@JsonAnyGetter
public Map<String, TimeSeriesInfo> getStockDailyData() {
    return stockDailyData;
}

@JsonAnySetter
public void setStockDailyData(String date, TimeSeriesInfo stockInfo) {
    this.stockDailyData.put(date, stockInfo);
}

@Override
public String toString() {
    return "HistoricalStock [metadata=" + metadata + ", stockDailyData=" + stockDailyData + "]";
}

}

And this is the code to deserialize the JSON using Jackson.

String fooResourceUrl = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=DEMO";
        ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
        ObjectMapper customMapper = new ObjectMapper();

        try {
            HistoricalStock msft = customMapper.readValue(response.getBody(), HistoricalStock.class);
            System.out.println(msft.getMetadata());
            System.out.println(msft.getStockDailyData().toString());

        } catch (IOException ioException) {
            ioException.printStackTrace();
        }

Here's the code for TimeSeries Class

@JsonIgnoreProperties(ignoreUnknown = true)
public class TimeSeriesInfo {
@JsonProperty("1. open")
private Double openingPrice;

@JsonProperty("2. high")
private Double highestPrice;

@JsonProperty("3. low")
private Double lowestPrice;

@JsonProperty("4. close")
private Double closingPrice;

@JsonProperty("5. volume")
private Long volume;

public TimeSeriesInfo() {
}

public Double getOpeningPrice() {
    return openingPrice;
}

public void setOpeningPrice(Double openingPrice) {
    this.openingPrice = openingPrice;
}

public Double getHighestPrice() {
    return highestPrice;
}

public void setHighestPrice(Double highestPrice) {
    this.highestPrice = highestPrice;
}

public Double getLowestPrice() {
    return lowestPrice;
}

public void setLowestPrice(Double lowestPrice) {
    this.lowestPrice = lowestPrice;
}

public Double getClosingPrice() {
    return closingPrice;
}

public void setClosingPrice(Double closingPrice) {
    this.closingPrice = closingPrice;
}

public Long getVolume() {
    return volume;
}

public void setVolume(Long volume) {
    this.volume = volume;
}

@Override
public String toString() {
    return "TimeSeries [openingPrice=" + openingPrice + ", highestPrice=" + highestPrice + ", lowestPrice="
            + lowestPrice + ", closingPrice=" + closingPrice + ", volume=" + volume + "]";
    }

}

2 个答案:

答案 0 :(得分:1)

在此特定示例中,您无需使用@JsonAnyGetter@JsonAnySetter批注。只需创建一个Map<String, TimeSeriesInfo>属性,它应该可以正常工作。另外,我建议使用BigDecimal代替DoubleLong。您可以在下面找到整个POJO的结构,该结构可以正常工作,而无需任何附加注释:

class DailySeries {

    @JsonProperty("Meta Data")
    private Metadata metadata;

    @JsonProperty("Time Series (Daily)")
    private Map<String, Daily> series;

    public Metadata getMetadata() {
        return metadata;
    }

    public void setMetadata(Metadata metadata) {
        this.metadata = metadata;
    }

    public Map<String, Daily> getSeries() {
        return series;
    }

    public void setSeries(Map<String, Daily> series) {
        this.series = series;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        String lineSeparator = System.lineSeparator();
        sb.append("metadata=").append(metadata).append(lineSeparator);
        series.forEach((k, s) -> sb.append(k).append(" = ").append(s).append(lineSeparator));

        return sb.toString();
    }
}

class Metadata {

    @JsonProperty("1. Information")
    private String information;

    @JsonProperty("2. Symbol")
    private String symbol;

    @JsonProperty("3. Last Refreshed")
    private String lastRefreshed;

    @JsonProperty("4. Output Size")
    private String outputSize;

    @JsonProperty("5. Time Zone")
    private String timeZone;

    public String getInformation() {
        return information;
    }

    public void setInformation(String information) {
        this.information = information;
    }

    public String getSymbol() {
        return symbol;
    }

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

    public String getLastRefreshed() {
        return lastRefreshed;
    }

    public void setLastRefreshed(String lastRefreshed) {
        this.lastRefreshed = lastRefreshed;
    }

    public String getOutputSize() {
        return outputSize;
    }

    public void setOutputSize(String outputSize) {
        this.outputSize = outputSize;
    }

    public String getTimeZone() {
        return timeZone;
    }

    public void setTimeZone(String timeZone) {
        this.timeZone = timeZone;
    }

    @Override
    public String toString() {
        return "Metadata{" +
                "information='" + information + '\'' +
                ", symbol='" + symbol + '\'' +
                ", lastRefreshed='" + lastRefreshed + '\'' +
                ", outputSize='" + outputSize + '\'' +
                ", timeZone='" + timeZone + '\'' +
                '}';
    }
}

class Daily {
    @JsonProperty("1. open")
    private BigDecimal open;

    @JsonProperty("2. high")
    private BigDecimal high;

    @JsonProperty("3. low")
    private BigDecimal low;

    @JsonProperty("4. close")
    private BigDecimal close;

    @JsonProperty("5. volume")
    private BigDecimal volume;

    public BigDecimal getOpen() {
        return open;
    }

    public void setOpen(BigDecimal open) {
        this.open = open;
    }

    public BigDecimal getHigh() {
        return high;
    }

    public void setHigh(BigDecimal high) {
        this.high = high;
    }

    public BigDecimal getLow() {
        return low;
    }

    public void setLow(BigDecimal low) {
        this.low = low;
    }

    public BigDecimal getClose() {
        return close;
    }

    public void setClose(BigDecimal close) {
        this.close = close;
    }

    public BigDecimal getVolume() {
        return volume;
    }

    public void setVolume(BigDecimal volume) {
        this.volume = volume;
    }

    @Override
    public String toString() {
        return "Daily{" +
                "open=" + open +
                ", high=" + high +
                ", low=" + low +
                ", close=" + close +
                ", volume=" + volume +
                '}';
    }
}

用法示例:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.math.BigDecimal;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        System.out.println(mapper.readValue(jsonFile, DailySeries.class));
    }
}

以上代码有效:

metadata=Metadata{information='Daily Prices (open, high, low, close) and Volumes', symbol='MSFT', lastRefreshed='2019-02-15', outputSize='Compact', timeZone='US/Eastern'}
2019-02-15 = Daily{open=107.9100, high=108.3000, low=107.3624, close=108.2200, volume=26606886}
2019-02-14 = Daily{open=106.3100, high=107.2900, low=105.6600, close=106.9000, volume=21784703}
2019-02-13 = Daily{open=107.5000, high=107.7800, low=106.7100, close=106.8100, volume=18394869}
2019-02-12 = Daily{open=106.1400, high=107.1400, low=105.4800, close=106.8900, volume=25056595}
2019-02-11 = Daily{open=106.2000, high=106.5800, low=104.9650, close=105.2500, volume=18914123}
2019-02-08 = Daily{open=104.3900, high=105.7800, low=104.2603, close=105.6700, volume=21461093}
2019-02-07 = Daily{open=105.1850, high=105.5900, low=104.2900, close=105.2700, volume=29760697}
2019-02-06 = Daily{open=107.0000, high=107.0000, low=105.5300, close=106.0300, volume=20609759}
2019-02-05 = Daily{open=106.0600, high=107.2700, low=105.9600, close=107.2200, volume=27325365}
2019-02-04 = Daily{open=102.8700, high=105.8000, low=102.7700, close=105.7400, volume=31315282}
2019-02-01 = Daily{open=103.7750, high=104.0999, low=102.3500, close=102.7800, volume=35535690}
2019-01-31 = Daily{open=103.8000, high=105.2200, low=103.1800, close=104.4300, volume=55636391}
2019-01-30 = Daily{open=104.6200, high=106.3800, low=104.3300, close=106.3800, volume=49471866}
2019-01-29 = Daily{open=104.8800, high=104.9700, low=102.1700, close=102.9400, volume=31490547}
2019-01-28 = Daily{open=106.2600, high=106.4800, low=104.6600, close=105.0800, volume=29476719}
2019-01-25 = Daily{open=107.2400, high=107.8800, low=106.5900, close=107.1700, volume=31218193}
2019-01-24 = Daily{open=106.8600, high=107.0000, low=105.3400, close=106.2000, volume=23164838}
2019-01-23 = Daily{open=106.1200, high=107.0400, low=105.3400, close=106.7100, volume=25874294}
2019-01-22 = Daily{open=106.7500, high=107.1000, low=104.8600, close=105.6800, volume=32371253}
2019-01-18 = Daily{open=107.4600, high=107.9000, low=105.9100, close=107.7100, volume=37427587}
2019-01-17 = Daily{open=105.0000, high=106.6250, low=104.7600, close=106.1200, volume=28393015}
2019-01-16 = Daily{open=105.2600, high=106.2550, low=104.9600, close=105.3800, volume=29853865}
2019-01-15 = Daily{open=102.5100, high=105.0500, low=101.8800, close=105.0100, volume=31587616}
2019-01-14 = Daily{open=101.9000, high=102.8716, low=101.2600, close=102.0500, volume=28437079}
2019-01-11 = Daily{open=103.1900, high=103.4400, low=101.6400, close=102.8000, volume=28314202}
2019-01-10 = Daily{open=103.2200, high=103.7500, low=102.3800, close=103.6000, volume=30067556}
2019-01-09 = Daily{open=103.8600, high=104.8800, low=103.2445, close=104.2700, volume=32280840}
2019-01-08 = Daily{open=103.0400, high=103.9700, low=101.7134, close=102.8000, volume=31514415}
2019-01-07 = Daily{open=101.6400, high=103.2681, low=100.9800, close=102.0600, volume=35656136}
2019-01-04 = Daily{open=99.7200, high=102.5100, low=98.9300, close=101.9300, volume=44060620}
2019-01-03 = Daily{open=100.1000, high=100.1850, low=97.2000, close=97.4000, volume=42578410}
2019-01-02 = Daily{open=99.5500, high=101.7500, low=98.9400, close=101.1200, volume=35329345}
2018-12-31 = Daily{open=101.2900, high=102.4000, low=100.4400, close=101.5700, volume=33173765}
2018-12-28 = Daily{open=102.0900, high=102.4100, low=99.5200, close=100.3900, volume=38169312}
2018-12-27 = Daily{open=99.3000, high=101.1900, low=96.4000, close=101.1800, volume=49498509}
2018-12-26 = Daily{open=95.1400, high=100.6900, low=93.9600, close=100.5600, volume=51634793}
2018-12-24 = Daily{open=97.6800, high=97.9700, low=93.9800, close=94.1300, volume=43935192}
2018-12-21 = Daily{open=101.6300, high=103.0000, low=97.4600, close=98.2300, volume=111242070}
2018-12-20 = Daily{open=103.0500, high=104.3100, low=98.7800, close=101.5100, volume=70334184}
2018-12-19 = Daily{open=103.6500, high=106.8800, low=101.3500, close=103.6900, volume=68198186}
2018-12-18 = Daily{open=103.7500, high=104.5100, low=102.5200, close=103.9700, volume=49319196}
2018-12-17 = Daily{open=105.4100, high=105.8000, low=101.7100, close=102.8900, volume=56957314}
2018-12-14 = Daily{open=108.2500, high=109.2600, low=105.5000, close=106.0300, volume=47043136}
2018-12-13 = Daily{open=109.5800, high=110.8700, low=108.6300, close=109.4500, volume=31333362}
2018-12-12 = Daily{open=110.8900, high=111.2700, low=109.0400, close=109.0800, volume=36183020}
2018-12-11 = Daily{open=109.8000, high=110.9500, low=107.4400, close=108.5900, volume=42381947}
2018-12-10 = Daily{open=104.8000, high=107.9800, low=103.8900, close=107.5900, volume=40801525}
2018-12-07 = Daily{open=108.3800, high=109.4500, low=104.3000, close=104.8200, volume=45044937}
2018-12-06 = Daily{open=105.8200, high=109.2400, low=105.0000, close=109.1900, volume=49107431}
2018-12-04 = Daily{open=111.9400, high=112.6373, low=108.2115, close=108.5200, volume=45196984}
2018-12-03 = Daily{open=113.0000, high=113.4200, low=110.7300, close=112.0900, volume=34732772}
2018-11-30 = Daily{open=110.7000, high=110.9700, low=109.3600, close=110.8900, volume=33665624}
2018-11-29 = Daily{open=110.3300, high=111.1150, low=109.0300, close=110.1900, volume=28123195}
2018-11-28 = Daily{open=107.8900, high=111.3300, low=107.8600, close=111.1200, volume=46788461}
2018-11-27 = Daily{open=106.2700, high=107.3300, low=105.3600, close=107.1400, volume=29124486}
2018-11-26 = Daily{open=104.7900, high=106.6300, low=104.5800, close=106.4700, volume=32336165}
2018-11-23 = Daily{open=102.1700, high=103.8099, low=102.0000, close=103.0700, volume=13823099}
2018-11-21 = Daily{open=103.6000, high=104.4300, low=102.2400, close=103.1100, volume=28130621}
2018-11-20 = Daily{open=101.8000, high=102.9700, low=99.3528, close=101.7100, volume=64052457}
2018-11-19 = Daily{open=108.2700, high=108.5600, low=103.5500, close=104.6200, volume=44773899}
2018-11-16 = Daily{open=107.0800, high=108.8800, low=106.8000, close=108.2900, volume=33502121}
2018-11-15 = Daily{open=104.9900, high=107.8000, low=103.9100, close=107.2800, volume=38505165}
2018-11-14 = Daily{open=108.1000, high=108.2600, low=104.4700, close=104.9700, volume=39495141}
2018-11-13 = Daily{open=107.5500, high=108.7400, low=106.6400, close=106.9400, volume=35374583}
2018-11-12 = Daily{open=109.4200, high=109.9600, low=106.1000, close=106.8700, volume=33621807}
2018-11-09 = Daily{open=110.8500, high=111.4500, low=108.7600, close=109.5700, volume=32039223}
2018-11-08 = Daily{open=111.8000, high=112.2100, low=110.9100, close=111.7500, volume=25644105}
2018-11-07 = Daily{open=109.4400, high=112.2400, low=109.4000, close=111.9600, volume=37901704}
2018-11-06 = Daily{open=107.3800, high=108.8400, low=106.2800, close=107.7200, volume=24340248}
2018-11-05 = Daily{open=106.3700, high=107.7400, low=105.9000, close=107.5100, volume=27922144}
2018-11-02 = Daily{open=106.4800, high=107.3200, low=104.9750, close=106.1600, volume=37680194}
2018-11-01 = Daily{open=107.0500, high=107.3200, low=105.5300, close=105.9200, volume=33384201}
2018-10-31 = Daily{open=105.4350, high=108.1400, low=105.3900, close=106.8100, volume=51062383}
2018-10-30 = Daily{open=103.6600, high=104.3800, low=100.1100, close=103.7300, volume=65350878}
2018-10-29 = Daily{open=108.1050, high=108.7000, low=101.6300, close=103.8500, volume=55162001}
2018-10-26 = Daily{open=105.6900, high=108.7500, low=104.7600, close=106.9600, volume=55523104}
2018-10-25 = Daily{open=106.5500, high=109.2700, low=106.1500, close=108.3000, volume=61646819}
2018-10-24 = Daily{open=108.4100, high=108.4900, low=101.5901, close=102.3200, volume=63897759}
2018-10-23 = Daily{open=107.7700, high=108.9700, low=105.1100, close=108.1000, volume=43770429}
2018-10-22 = Daily{open=109.3200, high=110.5400, low=108.2400, close=109.6300, volume=26545607}
2018-10-19 = Daily{open=108.9300, high=110.8600, low=108.2100, close=108.6600, volume=32785475}
2018-10-18 = Daily{open=110.1000, high=110.5300, low=107.8300, close=108.5000, volume=32506192}
2018-10-17 = Daily{open=111.6800, high=111.8100, low=109.5482, close=110.7100, volume=26548243}
2018-10-16 = Daily{open=109.5400, high=111.4100, low=108.9500, close=111.0000, volume=31610164}
2018-10-15 = Daily{open=108.9100, high=109.4800, low=106.9468, close=107.6000, volume=32068103}
2018-10-12 = Daily{open=109.0100, high=111.2400, low=107.1200, close=109.5700, volume=47742109}
2018-10-11 = Daily{open=105.3500, high=108.9300, low=104.2000, close=105.9100, volume=63904282}
2018-10-10 = Daily{open=111.2400, high=111.5000, low=105.7900, close=106.1600, volume=61376300}
2018-10-09 = Daily{open=111.1400, high=113.0800, low=110.8000, close=112.2600, volume=26198594}
2018-10-08 = Daily{open=111.6600, high=112.0300, low=109.3400, close=110.8500, volume=29640588}
2018-10-05 = Daily{open=112.6300, high=113.1700, low=110.6400, close=112.1300, volume=29068859}
2018-10-04 = Daily{open=114.6100, high=114.7588, low=111.6300, close=112.7900, volume=34821717}
2018-10-03 = Daily{open=115.4200, high=116.1800, low=114.9300, close=115.1700, volume=16648018}
2018-10-02 = Daily{open=115.3000, high=115.8400, low=114.4400, close=115.1500, volume=20787239}
2018-10-01 = Daily{open=114.7500, high=115.6800, low=114.7300, close=115.6100, volume=18883079}
2018-09-28 = Daily{open=114.1900, high=114.5700, low=113.6800, close=114.3700, volume=21647811}
2018-09-27 = Daily{open=114.7800, high=114.9100, low=114.2000, close=114.4100, volume=19091299}
2018-09-26 = Daily{open=114.4700, high=115.0550, low=113.7400, close=113.9800, volume=19352025}
2018-09-25 = Daily{open=114.8000, high=115.1000, low=113.7500, close=114.4500, volume=22668014}
2018-09-24 = Daily{open=113.0300, high=114.9000, low=112.2175, close=114.6700, volume=27334460}

以上代码已在2.9.8版中使用Jackson进行了测试

答案 1 :(得分:0)

michal ziober - 感谢您的出色回答! 为 kotlin 制作了我自己的版本 - 谁想要(:

data class DailyStock(
    @SerializedName("Meta Data")
    val metaData: MetaData,
    @SerializedName("Time Series (Daily)")
    val timeSeriesDaily: Map<String, TimeSeriesDaily>
)

data class MetaData(
    @SerializedName("1. Information")
    val information: String,
    @SerializedName("3. Last Refreshed")
    val lastRefreshed: String,
    @SerializedName("4. Output Size")
    val outputSize: String,
    @SerializedName("2. Symbol")
    val symbol: String,
    @SerializedName("5. Time Zone")
    val timeZone: String
)
data class TimeSeriesDaily (
    @SerializedName("1. open")
        val `open`: BigDecimal,
    @SerializedName("2. high")
        val high: BigDecimal,
    @SerializedName("3. low")
        val low: BigDecimal,
    @SerializedName("4. close")
        val close: BigDecimal,
    @SerializedName("5. adjusted close")
        val adjustedClose: BigDecimal,
    @SerializedName("6. volume")
        val volume: BigDecimal,
    @SerializedName("7. dividend amount")
        val dividendAmount: BigDecimal,
    @SerializedName("8. split coefficient")
        val splitCoefficient: BigDecimal,
    ){

    }