杰克逊:引用相同的对象

dab*_*aba 4 java json jackson

在某些情况下,在主体中序列化或反序列化的数据(例如,JSON主体)包含对同一对象的引用.例如,一个包含玩家列表的JSON主体,以及由这些玩家组成的团队列表:

{
  "players": [
    { "name": "Player 1" },
    { "name": "Player 2" },
    { "name": "Player 3" },
    { "name": "Player 4" },
    { "name": "Player 5" },
    { "name": "Player 6" },
    { "name": "Player 7" },
    { "name": "Player 8" }
  ],
  "teams": [
    {
      "name": "Team 1",
      "players": [
        { "name": "Player 1"},
        { "name": "Player 2"}
      ]
    },
    {
      "name": "Team 2",
      "players": [
        { "name": "Player 3"},
        { "name": "Player 4"}
      ]
    },
    {
      "name": "Team 3",
      "players": [
        { "name": "Player 5"},
        { "name": "Player 6"}
      ]
    },
    {
      "name": "Team 4",
      "players": [
        { "name": "Player 7"},
        { "name": "Player 8"}
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

可以想象,玩家X指的是同一个对象,但可能最终会出现一个不需要的场景,其中玩家X由不同的对象表示.

我想知道这些场景的最佳和最常见的方法是什么.我可以想到几种方法:

  1. Player类添加ID属性.我的设计不包含ID,因为它不需要.识别对象的方式是通过引用,如果它们包含在集合中,则通过它们在其中的位置(如果集合具有位置).这可能被认为是一种不好的做法,但我故意这样做,除非必要,否则我不打算改变它.
  2. 还有一个玩家ID,但它不是将球队序列化/反序列化为球员列表,而只是一个ID列表.JSON正文中包含的信息将丢失,但我们会有更紧凑的数据.
  3. 坚持我的无ID设计,与前一点类似,我可以有一个位置列表(实际上它实际上是一个玩家ID,因为它们作为识别手段),所以数字0指的是玩家球员名单中的第一个位置.
  4. 改变合同并让玩家拥有独特的名字.有了这个,我们现在可以拥有一个ID而无需向该类添加新属性.但是我认为这是一个坏主意,因为不一定所有球员都应该有不同的名字.

什么是最好的方法?通常做什么?你有不同的建议吗?

Sha*_*her 5

我达到了一个接近问题要求的东西:我使用了杰克逊的对象身份特征,它允许定义某个属性的值来识别POJO的不同实例:

@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, 
        property="name", scope=Player.class)
public class Player
{
    public String name;

    public Player() {}
    public Player(String name) { this.name = name; }

    public String toString() {
        // prints name and java object id 
        return name + "-" + super.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是使用的POJO的其余部分:

public class League
{
    public List<Player> players;
    public List<Team> teams;
}

public class Team
{
    public String name;
    public List<Player> players;

    public Team() {}
    public Team(String name) { this.name = name; }

    public String toString() {
        return name + "-" + super.toString() + ":" + players.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试方法:

public static void main(String[] args)
{
    ObjectMapper objectMapper = new ObjectMapper();

    try (Reader reader = new FileReader("C:/Temp/xx.json")) {
        League l = objectMapper.readValue(reader, League.class);
        System.out.println("l.players");
        System.out.println(l.players);
        System.out.println("l.teams");
        System.out.println(l.teams);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出清楚地表明在玩家和团队中使用相同的对象:

l.players
[Player 1-test.JSONTest$Player@641147d0, Player 2-test.JSONTest$Player@6e38921c, Player 3-test.JSONTest$Player@64d7f7e0, Player 4-test.JSONTest$Player@27c6e487, Player 5-test.JSONTest$Player@49070868, Player 6-test.JSONTest$Player@6385cb26, Player 7-test.JSONTest$Player@38364841, Player 8-test.JSONTest$Player@28c4711c]
l.teams
[Team 1-test.JSONTest$Team@59717824:[Player 1-test.JSONTest$Player@641147d0, Player 2-test.JSONTest$Player@6e38921c], Team 2-test.JSONTest$Team@146044d7:[Player 3-test.JSONTest$Player@64d7f7e0, Player 4-test.JSONTest$Player@27c6e487], Team 3-test.JSONTest$Team@1e9e725a:[Player 5-test.JSONTest$Player@49070868, Player 6-test.JSONTest$Player@6385cb26], Team 4-test.JSONTest$Team@15d9bc04:[Player 7-test.JSONTest$Player@38364841, Player 8-test.JSONTest$Player@28c4711c]]
Run Code Online (Sandbox Code Playgroud)

到目前为止这么好,为什么"接近要求​​的东西"呢?我不得不稍微改变输入json,以便杰克逊能够正确识别出球队中的球员是否参考球员名单中的球员:

{
  "players": [
    { "name": "Player 1" },
    { "name": "Player 2" },
    { "name": "Player 3" },
    { "name": "Player 4" },
    { "name": "Player 5" },
    { "name": "Player 6" },
    { "name": "Player 7" },
    { "name": "Player 8" }
  ],
  "teams": [
    {
      "name": "Team 1",
      "players": [ "Player 1", "Player 2"]
    },
    {
      "name": "Team 2",
      "players": [ "Player 3", "Player 4"]
    },
    {
      "name": "Team 3",
      "players": [ "Player 5", "Player 6"]
    },
    {
      "name": "Team 4",
      "players": [ "Player 7", "Player 8"]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)