java - jackson :引用同一个对象

标签 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"}
      ]
    }
  ]
}

正如您想象的那样,玩家 X 指的是同一个对象,但我们最终可能会遇到一个不需要的场景,即 玩家 X 由不同的对象表示。

我想知道这些情况下最好和最常用的方法是什么。我可以想到几种方法:

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

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

最佳答案

我达到了接近问题要求的程度: 我用了 jackson 的 Object Identity Feature它允许定义某个属性的值来标识 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();
    }
}

这是使用的其余 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();
    }
}

测试方法:

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

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

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]]

到目前为止一切顺利,那么为什么要“接近要求​​的东西”呢? 我不得不稍微更改输入 json,以便 Jackson 正确识别团队中的球员是对球员列表中球员的引用:

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

关于java - jackson :引用同一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37640985/

相关文章:

java - PHP API 中的语法错误

json - 使用 jackson 反序列化惰性列表

java - 如何在我的 Netbeans 项目中包含外部 jar

Java 解压缩用 zlib deflate 压缩的字符串

java - CSS 在运行程序时不起作用,但在我不运行时它确实起作用

javascript - AngularJS 根据日期检索 JSON 记录

java - 从 Java 应用程序发送时未在服务器中获取正确的 json

php - file_put_contents 在使用 json_encode 时返回 null

java - 如何将 JSON 字符串反序列化为放宽根值区分大小写的对象?

java - Spring 启动 MVC。传递空请求正文