3

How to deserialize a JSON String that contains lists of objects within other objects? I found explanations for simple deserialization, but I can't extrapolate much from them, as they're all a little bit off. As an example(POJOs ommited), for

String json = "[ {
  "id" : 33147,
  "name" : "Refinancing",
  "photos" : [ {
    "name" : "347.png",
    "url" : "/loans/568/photos/092"
  } ],
  "username" : "zach1985"
} , {
  "id" : 7693,
  "name" : "Stuff",
  "photos" : [ {
    "name" : "newpic1.png",
    "url" : "/loans/123446/photos/890"
  } ],
  "username" : "sengaia"
} ]";

ArrayList<Ad> ads = new ArrayList<>;

deserialize(json, ads);

System.out.println(ads.get(1).getName());
System.out.println(ads.get(0).getPhotos().get(0).getName());

The outputs would be "Stuff" and "347". How would then the deserialize() method need to be implemented?

8
  • You cant deserialize this to a arraylist. An arraylist only holds 1 key with no value. I suggest you use a HashMap. EDIT: Oops, I didnt see it was a JSON array. Commented Jun 2, 2016 at 19:29
  • @Martacus It's a JSON array. Commented Jun 2, 2016 at 19:29
  • 1
    Q: How to deserialize a JSON String that contains lists of objects within other objects? A: There are lots of different ways. If you're planning on working with JSON in Java more extensively, I'd recommend familiarizing yourself with Jackson: mkyong.com/java/how-to-convert-java-object-to-from-json-jackson Commented Jun 2, 2016 at 19:31
  • 1
    As others have indicated - learn a JSON framework like Jackson. Then use ObjectMapper to convert your JSON to objects. @Oleg indicated that you can use: new ObjectMapper().readValue(data, FullyTypedThing.class) - if you want to read an array, just pass in an array of that class to the same method, as in: new ObjectMapper().readValue(data, FullyTypedThing[].class Commented Jun 2, 2016 at 19:42
  • 1
    You might also need to configure the ObjectMapper depending on your requirements (Jackson has a few options). But I think just get started - and then try and tweak ObjectMapper if required by calling its #configure(..) and #setVisibility(..) methods. Commented Jun 2, 2016 at 19:45

1 Answer 1

2

As I indicated in the comment to the question here is the test that shows how to do this:

public class JSONTest {

  public static class FullyTypedThing {
    public int id;
    public String name;
    public List<Photos> photos = Lists.newArrayList();
    public String username;

    public static class Photos {
      public String name;
      public String url;
    }
  }

  private static final String json = "[ { \"id\" : 33147,    \"name\" : \"Refinancing\", \"photos\" : [ {"
    + "\"name\" : \"347.png\", \"url\" : \"/loans/568/photos/092\"  } ],"
    + "\"username\" : \"zach1985\"} , {  \"id\" : 7693,  \"name\" : \"Stuff\","
    + "\"photos\" : [ {  \"name\" : \"newpic1.png\",  \"url\" : \"/loans/123446/photos/890\"  } ],"
    + "\"username\" : \"sengaia\"  } ]";

  @Test
  public void roundtrip() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<FullyTypedThing> res = Lists.newArrayList(
      mapper.readValue(json, FullyTypedThing[].class));
    assertEquals(2, res.size());
    assertEquals(33147, res.get(0).id);
    assertEquals("Refinancing", res.get(0).name);
    assertEquals("347.png", res.get(0).photos.get(0).name);
    assertEquals("/loans/568/photos/092", res.get(0).photos.get(0).url);
    assertEquals(7693, res.get(1).id);
    assertEquals("Stuff", res.get(1).name);
    assertEquals("newpic1.png", res.get(1).photos.get(0).name);
    assertEquals("/loans/123446/photos/890", res.get(1).photos.get(0).url);

    assertEquals("[{\"id\":33147,\"name\":\"Refinancing\",\"photos\":"
      + "[{\"name\":\"347.png\",\"url\":\"/loans/568/photos/092\"}],"
      + "\"username\":\"zach1985\"},{\"id\":7693,\"name\":\"Stuff\","
      + "\"photos\":[{\"name\":\"newpic1.png\",\"url\":\"/loans/123446/photos/890\"}],"
      + "\"username\":\"sengaia\"}]", mapper.writeValueAsString(res));

  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

A few clarifications: 1) by "ObjectMapper", you mean "the Jackson library": github.com/FasterXML/jackson, 2) in your example, you use mapper.readValue(..., FullyTypedThing.class). This is OK. But Jackson ALSO allows you to access JSON entities WITHOUT necessarily defining a corresponding Java class, if needed.
Yes, I use Jackson, which is de-facto the standard. With respect to your second point, I fail to see the point. I know I can do that, so what? Why would I want untyped data and a lot of parsing code if I can have it properly typed and done in one line, transparent, clear and type-safe? Defining a holder class, like the one in this test, is a 5min work, even for more complex data structures. Yes, when working with heterogenous collections one might recourse to raw access, but then I would question the reasons behind that data being heterogeneous. More often than not it is poor design.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.