Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize with Jackson with reference to an existing object

Tags:

java

json

jackson

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?

like image 983
Rawr Avatar asked Dec 11 '16 00:12

Rawr


People also ask

How do you serialize an object to JSON Jackson in Java?

Converting Java object to JSON In it, create an object of the POJO class, set required values to it using the setter methods. Instantiate the ObjectMapper class. Invoke the writeValueAsString() method by passing the above created POJO object. Retrieve and print the obtained JSON.

How does Jackson deserialization work?

Jackson uses default (no argument) constructor to create object and then sets value using setters. so you only need @NoArgsConstructor and @Setter.

How does ObjectMapper readValue work?

The simple readValue API of the ObjectMapper is a good entry point. We can use it to parse or deserialize JSON content into a Java object. Also, on the writing side, we can use the writeValue API to serialize any Java object as JSON output.


2 Answers

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));
}
like image 89
Tomasz Gawel Avatar answered Oct 28 '22 05:10

Tomasz Gawel


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);
}
like image 43
teppic Avatar answered Oct 28 '22 05:10

teppic