使用 gson 解析嵌套的 json

Parsing a nested json using gson

我想做的是使用 Gson 将嵌套的 json 数据解析为 Java 对象,并使用自定义的 toString() 将其打印出来。

Json内容

{"data": [
    {
        "symbol": "BTC",
        "circulating_supply": 18975050,
        "last_updated": "2022-03-05T13:54:00.000Z",
        "total_supply": 18975050,
        "cmc_rank": 1,
        "self_reported_circulating_supply": null,
        "platform": null,
        "tags": [
            "mineable",
            "pow",
            "sha-256",
            "store-of-value",
            "state-channel",
            "coinbase-ventures-portfolio",
            "three-arrows-capital-portfolio",
            "polychain-capital-portfolio",
            "binance-labs-portfolio",
            "blockchain-capital-portfolio",
            "boostvc-portfolio",
            "cms-holdings-portfolio",
            "dcg-portfolio",
            "dragonfly-capital-portfolio",
            "electric-capital-portfolio",
            "fabric-ventures-portfolio",
            "framework-ventures-portfolio",
            "galaxy-digital-portfolio",
            "huobi-capital-portfolio",
            "alameda-research-portfolio",
            "a16z-portfolio",
            "1confirmation-portfolio",
            "winklevoss-capital-portfolio",
            "usv-portfolio",
            "placeholder-ventures-portfolio",
            "pantera-capital-portfolio",
            "multicoin-capital-portfolio",
            "paradigm-portfolio"
        ],
        "date_added": "2013-04-28T00:00:00.000Z",
        "quote": {"USD": {
            "fully_diluted_market_cap": 820131199762.62,
            "last_updated": "2022-03-05T13:54:00.000Z",
            "market_cap_dominance": 42.252,
            "percent_change_30d": 6.81621153,
            "percent_change_1h": -0.42008562,
            "percent_change_24h": -5.71623656,
            "market_cap": 741049072478.8419,
            "volume_change_24h": -11.0241,
            "price": 39053.8666553628,
            "percent_change_60d": -16.6843952,
            "volume_24h": 26123993408.855915,
            "percent_change_90d": -21.03603335,
            "percent_change_7d": -0.10097865
        }},
        "num_market_pairs": 9214,
        "name": "Bitcoin",
        "max_supply": 21000000,
        "id": 1,
        "self_reported_market_cap": null,
        "slug": "bitcoin"
    },
    {
        "symbol": "ETH",
        "circulating_supply": 119834013.5615,
        "last_updated": "2022-03-05T13:54:00.000Z",
        "total_supply": 119834013.5615,
        "cmc_rank": 2,
        "self_reported_circulating_supply": null,
        "platform": null,
        "tags": [
            "mineable",
            "pow",
            "smart-contracts",
            "ethereum-ecosystem",
            "coinbase-ventures-portfolio",
            "three-arrows-capital-portfolio",
            "polychain-capital-portfolio",
            "binance-labs-portfolio",
            "blockchain-capital-portfolio",
            "boostvc-portfolio",
            "cms-holdings-portfolio",
            "dcg-portfolio",
            "dragonfly-capital-portfolio",
            "electric-capital-portfolio",
            "fabric-ventures-portfolio",
            "framework-ventures-portfolio",
            "hashkey-capital-portfolio",
            "kenetic-capital-portfolio",
            "huobi-capital-portfolio",
            "alameda-research-portfolio",
            "a16z-portfolio",
            "1confirmation-portfolio",
            "winklevoss-capital-portfolio",
            "usv-portfolio",
            "placeholder-ventures-portfolio",
            "pantera-capital-portfolio",
            "multicoin-capital-portfolio",
            "paradigm-portfolio",
            "injective-ecosystem",
            "bnb-chain"
        ],
        "date_added": "2015-08-07T00:00:00.000Z",
        "quote": {"USD": {
            "fully_diluted_market_cap": 316405371023.81,
            "last_updated": "2022-03-05T13:54:00.000Z",
            "market_cap_dominance": 18.0363,
            "percent_change_30d": 1.39750424,
            "percent_change_1h": -0.82066438,
            "percent_change_24h": -3.20839994,
            "market_cap": 316405371023.81366,
            "volume_change_24h": -14.3764,
            "price": 2640.363629825611,
            "percent_change_60d": -31.31982292,
            "volume_24h": 12406258074.91051,
            "percent_change_90d": -37.45316954,
            "percent_change_7d": -4.71064229
        }},
        "num_market_pairs": 5543,
        "name": "Ethereum",
        "max_supply": null,
        "id": 1027,
        "self_reported_market_cap": null,
        "slug": "ethereum"
    },
 and so on...
]}

POJO 类 : 例子

package controller;

import java.util.List;
import javax.annotation.processing.Generated;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

@Generated("jsonschema2pojo")
public class Example {

    @SerializedName("data")
    @Expose
    private List<JsonFormatter> data = null;

    public List<JsonFormatter> getData() {
        return data;
    }

    public void setData(List<JsonFormatter> data) {
        this.data = data;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(Example.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
        sb.append("data");
        sb.append('=');
        sb.append(((this.data == null)?"<null>":this.data));
        sb.append(',');
        if (sb.charAt((sb.length()- 1)) == ',') {
            sb.setCharAt((sb.length()- 1), ']');
        } else {
            sb.append(']');
        }
        return sb.toString();
    }

}

POJO 类 : Json格式化程序

package controller;


import java.util.List;
import javax.annotation.processing.Generated;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

@Generated("jsonschema2pojo")
public class JsonFormatter {

    @SerializedName("symbol")
    @Expose
    private String symbol;
    @SerializedName("circulating_supply")
    @Expose
    private Float circulatingSupply;
    @SerializedName("last_updated")
    @Expose
    private String lastUpdated;
    @SerializedName("total_supply")
    @Expose
    private Float totalSupply;
    @SerializedName("cmc_rank")
    @Expose
    private Float cmcRank;
    @SerializedName("self_reported_circulating_supply")
    @Expose
    private Object selfReportedCirculatingSupply;
    @SerializedName("platform")
    @Expose
    private Platform platform;
    @SerializedName("tags")
    @Expose
    private List<String> tags = null;
    @SerializedName("date_added")
    @Expose
    private String dateAdded;
    @SerializedName("quote")
    @Expose
    private Quote quote;
    @SerializedName("num_market_pairs")
    @Expose
    private Float numMarketPairs;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("max_supply")
    @Expose
    private Float maxSupply;
    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("self_reported_market_cap")
    @Expose
    private Object selfReportedMarketCap;
    @SerializedName("slug")
    @Expose
    private String slug;

    public String getSymbol() {
        return symbol;
    }

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

    public Float getCirculatingSupply() {
        return circulatingSupply;
    }

    public void setCirculatingSupply(Float circulatingSupply) {
        this.circulatingSupply = circulatingSupply;
    }

    public String getLastUpdated() {
        return lastUpdated;
    }

    public void setLastUpdated(String lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    public Float getTotalSupply() {
        return totalSupply;
    }

    public void setTotalSupply(Float totalSupply) {
        this.totalSupply = totalSupply;
    }

    public Float getCmcRank() {
        return cmcRank;
    }

    public void setCmcRank(Float cmcRank) {
        this.cmcRank = cmcRank;
    }

    public Object getSelfReportedCirculatingSupply() {
        return selfReportedCirculatingSupply;
    }

    public void setSelfReportedCirculatingSupply(Object selfReportedCirculatingSupply) {
        this.selfReportedCirculatingSupply = selfReportedCirculatingSupply;
    }

    public Platform getPlatform() {
        return platform;
    }

    public void setPlatform(Platform platform) {
        this.platform = platform;
    }

    public List<String> getTags() {
        return tags;
    }

    public void setTags(List<String> tags) {
        this.tags = tags;
    }

    public String getDateAdded() {
        return dateAdded;
    }

    public void setDateAdded(String dateAdded) {
        this.dateAdded = dateAdded;
    }

    public Quote getQuote() {
        return quote;
    }

    public void setQuote(Quote quote) {
        this.quote = quote;
    }

    public Float getNumMarketPairs() {
        return numMarketPairs;
    }

    public void setNumMarketPairs(Float numMarketPairs) {
        this.numMarketPairs = numMarketPairs;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getMaxSupply() {
        return maxSupply;
    }

    public void setMaxSupply(Float maxSupply) {
        this.maxSupply = maxSupply;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Object getSelfReportedMarketCap() {
        return selfReportedMarketCap;
    }

    public void setSelfReportedMarketCap(Object selfReportedMarketCap) {
        this.selfReportedMarketCap = selfReportedMarketCap;
    }

    public String getSlug() {
        return slug;
    }

    public void setSlug(String slug) {
        this.slug = slug;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(JsonFormatter.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
        sb.append("symbol");
        sb.append('=');
        sb.append(((this.symbol == null)?"<null>":this.symbol));
        sb.append(',');
        sb.append("circulatingSupply");
        sb.append('=');
        sb.append(((this.circulatingSupply == null)?"<null>":this.circulatingSupply));
        sb.append(',');
        sb.append("lastUpdated");
        sb.append('=');
        sb.append(((this.lastUpdated == null)?"<null>":this.lastUpdated));
        sb.append(',');
        sb.append("totalSupply");
        sb.append('=');
        sb.append(((this.totalSupply == null)?"<null>":this.totalSupply));
        sb.append(',');
        sb.append("cmcRank");
        sb.append('=');
        sb.append(((this.cmcRank == null)?"<null>":this.cmcRank));
        sb.append(',');
        sb.append("selfReportedCirculatingSupply");
        sb.append('=');
        sb.append(((this.selfReportedCirculatingSupply == null)?"<null>":this.selfReportedCirculatingSupply));
        sb.append(',');
        sb.append("platform");
        sb.append('=');
        sb.append(((this.platform == null)?"<null>":this.platform));
        sb.append(',');
        sb.append("tags");
        sb.append('=');
        sb.append(((this.tags == null)?"<null>":this.tags));
        sb.append(',');
        sb.append("dateAdded");
        sb.append('=');
        sb.append(((this.dateAdded == null)?"<null>":this.dateAdded));
        sb.append(',');
        sb.append("quote");
        sb.append('=');
        sb.append(((this.quote == null)?"<null>":this.quote));
        sb.append(',');
        sb.append("numMarketPairs");
        sb.append('=');
        sb.append(((this.numMarketPairs == null)?"<null>":this.numMarketPairs));
        sb.append(',');
        sb.append("name");
        sb.append('=');
        sb.append(((this.name == null)?"<null>":this.name));
        sb.append(',');
        sb.append("maxSupply");
        sb.append('=');
        sb.append(((this.maxSupply == null)?"<null>":this.maxSupply));
        sb.append(',');
        sb.append("id");
        sb.append('=');
        sb.append(((this.id == null)?"<null>":this.id));
        sb.append(',');
        sb.append("selfReportedMarketCap");
        sb.append('=');
        sb.append(((this.selfReportedMarketCap == null)?"<null>":this.selfReportedMarketCap));
        sb.append(',');
        sb.append("slug");
        sb.append('=');
        sb.append(((this.slug == null)?"<null>":this.slug));
        sb.append(',');
        if (sb.charAt((sb.length()- 1)) == ',') {
            sb.setCharAt((sb.length()- 1), ']');
        } else {
            sb.append(']');
        }
        return sb.toString();
    }

}

我的 POJO 还有其他 类,我尝试将其解析为 Gson 的方式是:

Gson gson = new Gson();
Type type = new TypeToken<Map<String, ArrayList<JsonFormatter>>>() {}.getType();
Map<String, ArrayList<Example>> nodeProperties = gson.fromJson(json.toString(), type);

但是当我尝试打印出它的子值时

for (Map.Entry<String, ArrayList<Example>> set : nodeProperties.entrySet()) {
            System.out.println(set.getValue().get(0).getData().get(0).toString());
        }

我收到错误:

class controller.JsonFormatter cannot be cast to class controller.Example (controller.JsonFormatter and controller.Example are in unnamed module of loader 'app')

我想实现的是将上面的json内容打印成这样:

Symbol: BTC
Circulating_supply: 18975050
...
Tags:
    mineable

谁能帮我解决这个问题?提前致谢!

问题出在这些行中:

Type type = new TypeToken<Map<String, ArrayList<JsonFormatter>>>() {}.getType();
Map<String, ArrayList<Example>> nodeProperties = gson.fromJson(json.toString(), type);

TypeToken 用于 Map<String, ArrayList<<em>JsonFormatter</em>>>,但您存储已解析的 JSON 在类型为 Map<String, ArrayList<<em>Example</em>>> 的变量中。不幸的是 Gson.fromJson(..., Type) 不提供任何类型安全保证,因此您必须确保所提供的 Type 与您存储结果的变量类型相匹配。另外由于 Java 的类型在运行时擦除,您不会注意到 JsonFormatterExample 不匹配,直到您遍历元素,导致 ClassCastException.

根据您提供的 JSON 数据,在我看来您可以直接使用 gson.fromJson(json.toString(), Example.class),但请验证这对您的用例是否真的正确。