简体   繁体   中英

Deserialize with Jackson with reference to an existing object

JSON

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

}

How would I map the JSON into the following classes such that Bobby's school is mapped to the already instantiated School A.

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

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

I've tried some weird stuff with the Student class...

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

The problem I'm having is that both the schools and the students are being parsed from the JSON at the same time, so I'm not sure how to get a list of the schools. Maybe I should parse these separately so I have the list of schools first?

Jackson will do it for you. Just annotate your objects with @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);
}

With classes defined as below:

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

This works exactly as You intended:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM