0

I want to parse a JSON using Java and I get the following error : com.fasterxml.jackson.databind.exc.MismatchedInputException:com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.ArrayList<com.footbal.dtoStatistics.Statistics> out of START_OBJECT token at [Source: (String)"

My Json looks like this:

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

And the classes I used for the parsing are:

public class StatisticsResponse {

    Api api;

    public Api getApi() {
        return api;
    }

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

    int results;
    List<Statistics> statistics;

    public int getResults() {
        return results;
    }

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

    public List<Statistics> getStatistics() {
        return statistics;
    }

    public void setStatistics(List<Statistics> statistics) {
        this.statistics = statistics;
    }
}
public class Statistics {

    @JsonAlias({"Shots On Goal"})
    Stats ShotsonGoal;

    @JsonAlias({"Shots Off Goal"})
    Stats ShotsoffGoal;

    @JsonAlias({"Total Shots"})
    Stats TotalShots;

    @JsonAlias({"Blocked Shots"})
    Stats BlockedShots;

    @JsonAlias({"Shots insidebox"})
    Stats Shotsinsidebox;

    @JsonAlias({"Shots outsidebox"})
    Stats Shotsoutsidebox;
    Stats Fouls;

    @JsonAlias({"Corner Kicks"})
    Stats CornerKicks;
    Stats Offsides;

    @JsonAlias({"Ball Possession"})
    Stats BallPossesion;

    @JsonAlias({"Yellow Cards"})
    Stats YellowCards;

    @JsonAlias({"Red Cards"})
    Stats RedCards;

    @JsonAlias({"Goalkeeper Saves"})
    Stats GoalkeeperSaves;

    @JsonAlias({"Total passes"})
    Stats Totalpasses;

    @JsonAlias({"Passes accurate"})
    Stats Passesaccurate;

    @JsonAlias({"Passes %"})
    Stats 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 Stats getBallPossesion() {
        return BallPossesion;
    }

    public void setBallPossesion(Stats 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 Stats getPasses() {
        return Passes;
    }

    public void setPasses(Stats passes) {
        Passes = passes;
    }
public class Stats {

    int home;
    int away;

    public int getHome() {
        return home;
    }

    public void setHome(int home) {
        this.home = home;
    }

    public int getAway() {
        return away;
    }

    public void setAway(int away) {
        this.away = away;
    }
}
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();

I think my problem may come from the fact that the name of the values in the statistics array contain spaces and I think there is an issue with the JsonAlias stuff, but I don't know how else to declare it.

Can anyone help me with this parsing?

3 Answers 3

1

Your Json is not having List of statistics, it is JSON Object

 "statistics": { 

If its a List, it should be,

["statistics": {

So, if you don't want List, use only Statistics,

public class Api {
    int results;
    Statistics statistics;
}
Sign up to request clarification or add additional context in comments.

2 Comments

you are right, I got rid of the exception, but all my variables in the result seem to be null. It does not map the variables from Statistics class to the JSON field names. May it be from the Json Alias thing?
` @JsonAlias` defines one or more alternative names for a property to be accepted during deserialization i.e. setting JSON data to Java object. But at the time of serialization i.e. while getting JSON from Java object, the actual logical property name is used and not an alias. So use @JsonProperty. concretepage.com/jackson-api/…
0

The following changes need to be applied to existing data model:

  1. Change type List<Statistics> to Statistics as suggested earlier:
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;
    }
}
  1. Change @JsonAlias to @JsonProperty,
  2. Change type of BallPossesion and Passes to StatsPercent
  3. Add @JsonAutoDetect to disable duplicate output in serialization
@JsonAutoDetect(
        fieldVisibility = Visibility.ANY, 
        getterVisibility = Visibility.NONE, 
        setterVisibility = Visibility.NONE)
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;

// ... getters/setters
}
  1. Provide class to properly parse percent data

Update: you may use @JsonDeserialize/@JsonSerialize annotations and implement custom converters

public class StatsPercent {

    @JsonSerialize  (converter = IntToPercentConverter.class)
    @JsonDeserialize(converter = PercentToIntConverter.class)
    int home;

    @JsonSerialize  (converter = IntToPercentConverter.class)
    @JsonDeserialize(converter = PercentToIntConverter.class)
    int away;

    public int getHome() { return home; }
    public void setHome(int home) { this.home = home; }

    public int getAway() { return away; }
    public void setAway(int away) { this.away = away; }
}

public class IntToPercentConverter extends StdConverter<Integer, String> {

    @Override
    public String convert(Integer arg) {
        return arg.toString() + "%";
    }
}

public class PercentToIntConverter extends StdConverter<String, Integer> {

    @Override
    public Integer convert(String arg) {
        if (null != arg) {
            return Integer.parseInt(arg.replace("%", ""));
        }
        return null;
    }   
}


1 Comment

You're welcome! You may check out the update with custom deserialization of the percents to int values in StatsPercent class.
0

I think only way forward is to change

    List<Statistics> statistics;

to

    Map<String,Stats> statistics;

remove the Statistics class and access its fields via Map

1 Comment

You could write a test program to write the JSON using the StatisticsResponse object and see what it should look like.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.