【问题标题】:Deserialize with Jackson with reference to an existing object参考现有对象使用 Jackson 反序列化
【发布时间】:2017-04-26 04:33:30
【问题描述】:

JSON

{
  "schools": [
    {
      "id": 1,
      "name": "School A"
    },
    {
      "id": 2,
      "name": "School B"
    }
  ],
  "students": [
    {
      "id": 1,
      "name": "Bobby",
      "school": 1
    }
  ]

}

我如何将 JSON 映射到以下类中,以便将 Bobby 的学校映射到已经实例化的 School A。

public class School {
  private Integer id;
  private String name;
}

public class Student {
  private Integer id;
  private String name;
  private School school;
}

我在 Student 类中尝试了一些奇怪的东西...

public class Student {
  private Integer id;
  private String name;
  private School school;

  @JsonProperty("school")
  public void setSchool(Integer sid) {
    for (School school : getSchools()) {
      if (school.id == sid) {
        this.school = school;
        break;
      }
    }
  }
}

我遇到的问题是同时从 JSON 中解析学校和学生,所以我不确定如何获取学校列表。也许我应该分别解析这些,以便我首先获得学校列表?

【问题讨论】:

  • 你试过了吗?目前尚不清楚您遇到了什么问题。
  • 很抱歉,我试图通过一个我一直在尝试采用的方法的示例来更好地解释我试图解决的问题。

标签: java json jackson


【解决方案1】:

杰克逊会为你做这件事。只需使用 @JsonIdentityInfo 注释您的对象:

@JsonIdentityInfo(scope=School.class, generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class School {
    private Integer id;
    private String name;

    public School() {
    }

    public School(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@JsonIdentityInfo(scope=Student.class, generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Student {
    private Integer id;
    private String name;
    private School school;

    public Student() {
    }

    public Student(Integer id, String name, School school) {
        this.id = id;
        this.name = name;
        this.school = school;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }
}

public static void main(String[] args) throws IOException {
    School school = new School(1, "St Magdalene's");
    Student mary = new Student(1, "Mary", school);
    Student bob = new Student(2, "Bob", school);
    Student[] students = new Student[] {mary, bob};

    // Write out
    String serialized = mapper.writeValueAsString(students);
    System.out.println("Serialized: " + serialized);
    // Read in
    Student[] deserialized = mapper.readValue(serialized, Student[].class);
}

【讨论】:

  • 没用。序列化它看起来像:[{"id":1,"name":"Mary","school":{"id":1,"name":"St Magdalene's"}},{"id":2,"name":"Bob","school":1}] 反序列化它不链接到学校对象,而是只存储学校的 id。
  • 对不起,我应该检查一下结果。如果没有类型信息,则反序列化为哈希集列表。我更新了示例以使用 Student[] 以便杰克逊有足够的信息来构建对象。
  • 作为替代方案,您可以让 Jackson 管理 id。删除id 属性并使用generator= ObjectIdGenerators .IntSequenceGenerator
  • 我在使用默认属性 @id 时遇到了反序列化问题 (JsonMappingException: Unexpected end-of-input: was expecting closing),所以我不得不使用另一个。请注意,@JsonIdentityInfo 中定义的属性名称不需要存在于 Java 对象中(您可以定义任何名称,例如 myJacksonId)。最后我只在School 类上使用了@JsonIdentityInfo(scope=School.class, generator= ObjectIdGenerators.IntSequenceGenerator.class, property = "myJacksonId")Student 类不需要它)。
【解决方案2】:

类定义如下:

@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class)
class School {
    public Integer id;
    public String name;
}

class Student {
    public Integer id;
    public String name;
    @JsonIdentityReference(alwaysAsId = true)
    public School school;
}

class All {
    public List<School> schools;
    public List<Student> students;
}

这完全符合您的预期:

@Test
public void test() throws JsonProcessingException {
    var json = "{" +
            "\"schools\":[" +
            "{\"id\":1,\"name\":\"School A\"}," +
            "{\"id\":2,\"name\":\"School B\"}" +
            "]," +
            "\"students\":[" +
            "{\"id\":1,\"name\":\"Bobby\",\"school\":1}" +
            "]" +
            "}";
    var mapper = new ObjectMapper();
    var all =  mapper.readValue(json, All.class);
    Assertions.assertThat(all.students.get(0).school).isSameAs(all.schools.get(0));
}

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 2014-02-12
    • 2022-01-22
    • 2021-06-03
    • 1970-01-01
    • 2020-07-21
    • 2018-12-26
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多