3

I have a JSON structure similar to this:

"teams": {
    "team1Id": "team1Name",
    "team2Id": "team2Name"
}

and I would like to deserialize it to these Java classes:

class Teams {
Team team1;
Team team2;
}

class Team {
String id;
String name;
}

As you can see team1Id and team2Id, which are JSON keys, should be converted into values of Java fields. Additionally, the first teamId/teamName pair should be attributed to the object stored in team1, while the second pair is stored in the team2 field.

Are there any native JACKSON mappers to do this, or will I need to create my own custom deserializer for this?

andresp
  • 1,624
  • 19
  • 31
  • That JSON, although valid doesn't match the semantics of your class. You will need to write your custom deserializer. What you have is a format all on its own. – Sotirios Delimanolis Sep 26 '13 at 16:13
  • You are completely right. Although, this is JSON retrieved from a third party. I do not control its schema. – andresp Sep 26 '13 at 16:17
  • It's really weird. Could you show how result Teams object should look like after deserialization? I mean, if I invoke toString() method on Teams object, what it should print? => [Teams team1 = [Team id = team1Name, name = null],team2 = [Team id = team2Name, name = null]? – Michał Ziober Sep 26 '13 at 22:51
  • No. It would be something like this: [Teams team1 = [Team id = team1Id, name = team1Name], team2 = [Team id = team2Id, name = team2Name] – andresp Sep 26 '13 at 23:04

1 Answers1

2

You can implement custom deserializer for this class, but, I think, much simpler solution will be using @JsonAnySetter annotation.

class Teams {

    Team team1 = new Team();
    Team team2 = new Team();

    @JsonAnySetter
    public void anySetter(String key, String value) {
        if (key.startsWith("team1")) {
            team1.setId(key);
            team1.setName(value);
        } else if (key.startsWith("team2")) {
            team2.setId(key);
            team2.setName(value);
        }
    }

    //getters, setterr, toString()
}

Example usage:

import java.io.File;
import java.io.IOException;

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

public class JacksonProgram {

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Wrapper wrapper = mapper.readValue(new File("X:/json"), Wrapper.class);
        System.out.println(wrapper.getTeams());
    }
}

class Wrapper {

    private Teams teams;

    public Teams getTeams() {
        return teams;
    }

    public void setTeams(Teams teams) {
        this.teams = teams;
    }
}

Above program prints:

Teams [team1=Team [id=team1Id, name=team1Name], team2=Team [id=team2Id, name=team2Name]]

for this JSON:

{
    "teams": {
        "team1Id": "team1Name",
        "team2Id": "team2Name"
    }
}

### EDIT 1 ###

If your JSON looks like that:

{
    "teams": {
        "12345": "Chelsea",
        "67890": "Tottenham"
    }
}

I propose to deserialize it to LinkedHashMap<String, String> and after that convert it to Teams object. Example program:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonProgram {

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Wrapper wrapper = mapper.readValue(new File("X:/json"), Wrapper.class);
        System.out.println(wrapper.toTeams());
    }
}

class Wrapper {

    private LinkedHashMap<String, String> teams;

    public LinkedHashMap<String, String> getTeams() {
        return teams;
    }

    public void setTeams(LinkedHashMap<String, String> teams) {
        this.teams = teams;
    }

    public Teams toTeams() {
        List<Team> teamList = toTeamList();

        Teams result = new Teams();
        result.setTeam1(teamList.get(0));
        result.setTeam2(teamList.get(1));
        return result;
    }

    private List<Team> toTeamList() {
        List<Team> teamList = new ArrayList<Team>(teams.size());
        for (Entry<String, String> entry : teams.entrySet()) {
            Team team = new Team();
            team.setId(entry.getKey());
            team.setName(entry.getValue());
            teamList.add(team);
        }

        return teamList;
    }
}

Above program prints:

Teams [team1=Team [id=12345, name=Chelsea], team2=Team [id=67890, name=Tottenham]]
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • Thanks. I can't use "team1" and "team2" prefixes to identify the properties. team1 and team2 are variables, just as team1Name and team2Name. I just introduced them to infer the semantics behind the parsing. An instance of a concrete JSON would be something like this: "teams": { "12345": "Chelsea", "67890": "Tottenham" } Still, using the AnySetter looks like an interesting approach as long as I can infer the order the key-value pairs appear in the JSON (first team should be stored in team1 field and the second team in team2 field). Is it possible? – andresp Sep 27 '13 at 08:57