【问题标题】:JSON parsing issue when the response does not contain values响应不包含值时的 JSON 解析问题
【发布时间】:2020-04-26 11:20:36
【问题描述】:

我想使用 Java 解析 JSON,并且当我收到来自 GET 调用的值的响应时,我设法做到了这一点。当响应没有值时出现我的问题,因为我得到了异常:com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.footbal.dtoStatistics.Statistics out of START_ARRAY token

[Source: (String)"{"api":{"results":0,"statistics":[]}}"; line: 1, column: 34] (through reference chain: com.footbal.dtoStatistics.StatisticsResponse["api"]->com.footbal.dtoStatistics.Api["statistics"])

我没有值的 JSON 如下所示:

{
    "api": {
        "results": 0,
        "statistics": []
    }
}

我的 Json 及其解析工作的值如下所示:

{
    "api": {
        "results": 16,
        "statistics": {
            "Shots on Goal": {
                "home": "3",
                "away": "9"
            },
            "Shots off Goal": {
                "home": "5",
                "away": "3"
            },
            "Total Shots": {
                "home": "11",
                "away": "16"
            },
            "Blocked Shots": {
                "home": "3",
                "away": "4"
            },
            "Shots insidebox": {
                "home": "4",
                "away": "14"
            },
            "Shots outsidebox": {
                "home": "7",
                "away": "2"
            },
            "Fouls": {
                "home": "10",
                "away": "13"
            },
            "Corner Kicks": {
                "home": "7",
                "away": "4"
            },
            "Offsides": {
                "home": "2",
                "away": "1"
            },
            "Ball Possession": {
                "home": "55%",
                "away": "45%"
            },
            "Yellow Cards": {
                "home": "0",
                "away": "2"
            },
            "Red Cards": {
                "home": null,
                "away": null
            },
            "Goalkeeper Saves": {
                "home": "7",
                "away": "1"
            },
            "Total passes": {
                "home": "543",
                "away": "436"
            },
            "Passes accurate": {
                "home": "449",
                "away": "355"
            },
            "Passes %": {
                "home": "83%",
                "away": "81%"
            }
        }
    }
}

我用于解析的类是:

public class StatisticsResponse {

    Api api;

    public Api getApi() {
        return api;
    }

    public void setApi(Api api) {
        this.api = api;
    }
}
public class Api {

    int results;
    Statistics statistics;

    public int getResults() {
        return results;
    }

    public void setResults(int results) {
        this.results = results;
    }

    public Statistics getStatistics() {
        return statistics;
    }

    public void setStatistics(Statistics statistics) {
        this.statistics = statistics;
    }
}
@JsonAutoDetect(
        fieldVisibility = JsonAutoDetect.Visibility.ANY,
        getterVisibility = JsonAutoDetect.Visibility.NONE,
        setterVisibility = JsonAutoDetect.Visibility.NONE)
public class Statistics {

    @JsonProperty ("Shots on Goal")
    Stats ShotsonGoal;

    @JsonProperty ("Shots off Goal")
    Stats ShotsoffGoal;

    @JsonProperty ("Total Shots")
    Stats TotalShots;

    @JsonProperty ("Blocked Shots")
    Stats BlockedShots;

    @JsonProperty ("Shots insidebox")
    Stats Shotsinsidebox;

    @JsonProperty ("Shots outsidebox")
    Stats Shotsoutsidebox;
    Stats Fouls;

    @JsonProperty ("Corner Kicks")
    Stats CornerKicks;
    Stats Offsides;

    @JsonProperty ("Ball Possession")
    StatsPercent BallPossesion;

    @JsonProperty ("Yellow Cards")
    Stats YellowCards;

    @JsonProperty ("Red Cards")
    Stats RedCards;

    @JsonProperty ("Goalkeeper Saves")
    Stats GoalkeeperSaves;

    @JsonProperty ("Total passes")
    Stats Totalpasses;

    @JsonProperty ("Passes accurate")
    Stats Passesaccurate;

    @JsonProperty("Passes %")
    StatsPercent Passes;

    public Stats getShotsonGoal() {
        return ShotsonGoal;
    }

    public void setShotsonGoal(Stats shotsonGoal) {
        ShotsonGoal = shotsonGoal;
    }

    public Stats getShotsoffGoal() {
        return ShotsoffGoal;
    }

    public void setShotsoffGoal(Stats shotsoffGoal) {
        ShotsoffGoal = shotsoffGoal;
    }

    public Stats getTotalShots() {
        return TotalShots;
    }

    public void setTotalShots(Stats totalShots) {
        TotalShots = totalShots;
    }

    public Stats getBlockedShots() {
        return BlockedShots;
    }

    public void setBlockedShots(Stats blockedShots) {
        BlockedShots = blockedShots;
    }

    public Stats getShotsinsidebox() {
        return Shotsinsidebox;
    }

    public void setShotsinsidebox(Stats shotsinsidebox) {
        Shotsinsidebox = shotsinsidebox;
    }

    public Stats getShotsoutsidebox() {
        return Shotsoutsidebox;
    }

    public void setShotsoutsidebox(Stats shotsoutsidebox) {
        Shotsoutsidebox = shotsoutsidebox;
    }

    public Stats getFouls() {
        return Fouls;
    }

    public void setFouls(Stats fouls) {
        Fouls = fouls;
    }

    public Stats getCornerKicks() {
        return CornerKicks;
    }

    public void setCornerKicks(Stats cornerKicks) {
        CornerKicks = cornerKicks;
    }

    public Stats getOffsides() {
        return Offsides;
    }

    public void setOffsides(Stats offsides) {
        Offsides = offsides;
    }

    public StatsPercent getBallPossesion() {
        return BallPossesion;
    }

    public void setBallPossesion(StatsPercent ballPossesion) {
        BallPossesion = ballPossesion;
    }

    public Stats getYellowCards() {
        return YellowCards;
    }

    public void setYellowCards(Stats yellowCards) {
        YellowCards = yellowCards;
    }

    public Stats getRedCards() {
        return RedCards;
    }

    public void setRedCards(Stats redCards) {
        RedCards = redCards;
    }

    public Stats getGoalkeeperSaves() {
        return GoalkeeperSaves;
    }

    public void setGoalkeeperSaves(Stats goalkeeperSaves) {
        GoalkeeperSaves = goalkeeperSaves;
    }

    public Stats getTotalpasses() {
        return Totalpasses;
    }

    public void setTotalpasses(Stats totalpasses) {
        Totalpasses = totalpasses;
    }

    public Stats getPassesaccurate() {
        return Passesaccurate;
    }

    public void setPassesaccurate(Stats passesaccurate) {
        Passesaccurate = passesaccurate;
    }

    public StatsPercent getPasses() {
        return Passes;
    }

    public void setPasses(StatsPercent passes) {
        Passes = passes;
    }
}
try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JavaTimeModule());
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            StatisticsResponse apiResponse = mapper.readValue(statisticsResponse, StatisticsResponse.class);


                statisticsList = apiResponse.getApi().getStatistics();

为什么它适用于有值的情况,而我没有得到值的情况会失败?我看不出我做错了什么。

谁能帮我解析一下?

【问题讨论】:

  • 问题出在生成 JSON 的代码中。当您没有任何值时,它为api.statistics 提供一个数组([]),但是当有值时,它提供一个对象({...})。它应该始终提供一个对象,即使没有值:{}。或者,它应该提供null。但是在一种情况下提供[],在另一种情况下提供{...}……不是最佳实践。 :-)
  • 我该怎么办?我的代码应该如何处理这个问题?因为我无法更改 API 的外观
  • 嗨@Maria1995,该问题的解决方案非常简单——将statistics 设为无类型,将其类型更改为对象,详情请查看the answer

标签: java json


【解决方案1】:

在您的情况下,具有值和不具有值的 Json 是不同的。如果没有值,您的 JSON 会将统计信息作为列表。而另一种情况,它不是一个列表。您的类满足存在值的第二种情况。当没有值时,Api 类应该包含List<Statistics> 而不是Statistics

理想情况下,两种情况都尝试遵循相同的结构。如果永远不会列出统计信息,则更改:

{
    "api": {
        "results": 0,
        "statistics": []
    }
}

{
    "api": {
        "results": 0,
        "statistics": {}
    }
}

否则如果Statistics将返回List,则更改

{
    "api": {
        "results": 16,
        "statistics": {
            "Shots on Goal": {
                "home": "3",
                "away": "9"
            },
            "Shots off Goal": {
                "home": "5",
                "away": "3"
            },...
        }}}

{
    "api": {
        "results": 16,
        "statistics": [{
            "Shots on Goal": {
                "home": "3",
                "away": "9"
            },
            "Shots off Goal": {
                "home": "5",
                "away": "3"
            },...
        }]
      }}

【讨论】:

  • 问题是我无法更改 API...我只是它的用户。我的代码应该如何处理这种情况?
【解决方案2】:

解决此问题的方法非常简单:将statistics 的类型更改为Object 并更新getter/setter 和untyped mapping 即可。

class Api {
    int results;
    Object statistics;

    public int getResults() {
        return results;
    }

    public void setResults(int results) {
        this.results = results;
    }

    public Object getStatistics() {
        return statistics;
    }

    public void setStatistics(Object statistics) {
        this.statistics = statistics;
    } 
}

测试代码产生预期的输出:

String emptyStats = "{\n" + 
            "    \"api\": {\n" + 
            "        \"results\": 0,\n" + 
            "        \"statistics\": []\n" + 
            "     }\n" + 
            "}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//StatisticsResponse apiResponse = mapper.readValue(json, StatisticsResponse.class);
StatisticsResponse apiResponse = mapper.readValue(emptyStats, StatisticsResponse.class);

String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(apiResponse);
System.out.println(json);

// ----------------
{
  "api" : {
    "results" : 0,
    "statistics" : [ ]
  }
}

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 2021-08-04
    相关资源
    最近更新 更多