Java - 如何反序列化一个包含嵌套对象和列表的 JSON 数组?

3

如何反序列化包含其他对象中的对象列表的JSON字符串?我找到了有关简单反序列化的解释,但是我不能从中推断太多,因为它们都有点偏离。例如(省略了POJOs),

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

输出将是"Stuff"和"347"。那么反序列化方法如何实现呢?

1
Q: 如何反序列化包含其他对象中的对象列表的JSON字符串?A:有很多不同的方法。如果您计划更广泛地在Java中使用JSON,我建议您熟悉Jackson:http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/ - paulsm4
1
正如其他人所指出的那样 - 学习像Jackson这样的JSON框架。然后使用ObjectMapper将您的JSON转换为对象。@Oleg指出,您可以使用:new ObjectMapper().readValue(data, FullyTypedThing.class) - 如果要读取数组,只需将该类的数组传递给相同的方法,例如:new ObjectMapper().readValue(data, FullyTypedThing[].class) - dutoitns
1
根据您的需求,您可能还需要配置ObjectMapper(Jackson有一些选项)。但我认为最好先开始 - 然后尝试调整ObjectMapper,如果需要,可以通过调用其#configure(..)#setVisibility(..)方法进行调整。 - dutoitns
@Oleg,我会先尝试将提供的示例应用到我的情况中,谢谢。 - Sargon1
我在答案中放了可运行的示例。我认为它不是重复的,因为原始答案相当无聊(我的意思是重复的问题和对原始问题的回答)... - Oleg Sklyar
显示剩余3条评论
1个回答

2

正如我在对问题的评论中所指出的,这里是展示如何做到这一点的测试:

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

  }
}

一些澄清:1)通过“ObjectMapper”,您指的是“Jackson库”:https://github.com/FasterXML/jackson,2)在您的示例中,您使用`mapper.readValue(...,FullyTypedThing.class)`。这是可以的。但是,如果需要,Jackson还允许您访问JSON实体*WITHOUT*必须定义相应的Java类。 - paulsm4
1
是的,我使用Jackson,这是事实上的标准。关于您提出的第二点,我不明白其中的意义。我知道我可以这样做,那又怎样呢?如果我可以正确地进行类型定义并在一行中完成,透明、清晰和类型安全,为什么要使用未经分类的数据和大量解析代码呢?像这个测试中的那个持有者类一样定义一个持有者类只需要5分钟的工作时间,即使对于更复杂的数据结构也是如此。是的,当使用异构集合时,可能会回到原始访问,但那么我会质疑数据异构背后的原因。往往情况下,这是设计不良所致。 - Oleg Sklyar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接