通过使用键作为值来反序列化Jackson

3

我有一个类似于下面这样的JSON结构:

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

我希望将其反序列化为这些Java类:

class Teams {
Team team1;
Team team2;
}

class Team {
String id;
String name;
}

正如您所看到的,team1Id和team2Id是JSON键,应转换为Java字段的值。此外,第一个teamId/teamName对应于存储在team1中的对象,而第二个对应于存储在team2字段中的对象。

是否有任何本地的JACKSON映射器可以做到这一点,还是我需要创建自己的自定义反序列化器?


那个 JSON 虽然有效,但不符合你的类的语义。你需要编写自定义反序列化器。你所拥有的是一种独特的格式。 - Sotirios Delimanolis
你是完全正确的。虽然这是从第三方检索到的JSON数据。我无法控制它的架构。 - andresp
这真的很奇怪。你能展示一下反序列化后的Teams对象应该是什么样子吗?我的意思是,如果我在Teams对象上调用toString()方法,它应该打印什么? => [Teams team1 = [Team id = team1Name, name = null],team2 = [Team id = team2Name, name = null] - Michał Ziober
不,它会是这样的: [Teams team1 = [Team id = team1Id, name = team1Name], team2 = [Team id = team2Id, name = team2Name] - andresp
1个回答

2
您可以为这个类实现自定义的反序列化器,但我认为更简单的解决方案是使用@JsonAnySetter注释。
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()
}

使用示例:

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;
    }
}

上面的程序打印输出:
Teams [team1=Team [id=team1Id, name=team1Name], team2=Team [id=team2Id, name=team2Name]]

针对这个JSON:

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

如果你的JSON长这样:
{
    "teams": {
        "12345": "Chelsea",
        "67890": "Tottenham"
    }
}

我建议将其反序列化为LinkedHashMap<String,String>,然后将其转换为Teams对象。示例程序如下:
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;
    }
}

上面的程序输出:
Teams [team1=Team [id=12345, name=Chelsea], team2=Team [id=67890, name=Tottenham]]

谢谢。我不能使用“team1”和“team2”前缀来识别属性。team1和team2是变量,就像team1Name和team2Name一样。我只是引入它们来推断解析背后的语义。具体JSON实例可能如下所示:“teams”:{  “12345”:“切尔西”,  “67890”:“托特纳姆” }尽管如此,使用AnySetter似乎是一种有趣的方法,只要我可以推断出键值对在JSON中出现的顺序(第一个团队应存储在team1字段中,第二个团队应存储在team2字段中)。这是可能的吗? - andresp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接