使用Jackson将JSON反序列化为ArrayList <POJO>


97

我有一个Java类MyPojo,我对从JSON反序列化感兴趣。我已经配置了一个特殊的MixIn类MyPojoDeMixIn,以协助我进行反序列化。MyPojo只有intString实例变量与适当的getter和setter方法相结合。MyPojoDeMixIn看起来像这样:

public abstract class MyPojoDeMixIn {
  MyPojoDeMixIn(
      @JsonProperty("JsonName1") int prop1,
      @JsonProperty("JsonName2") int prop2,
      @JsonProperty("JsonName3") String prop3) {}
}

在我的测试客户端中,我执行以下操作,但是它在编译时当然不起作用,因为JsonMappingException与类型不匹配有关。

ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }

我知道可以通过创建一个仅包含其中一个的“ Response”对象来缓解此问题ArrayList<MyPojo>,但是随后我将不得不为我想返回的每个单个类型创建这些有点无用的对象。

我也在线查看了JacksonInFiveMinutes,但经历了一段糟糕的时光,了解了有关这些问题Map<A,B>及其与我的问题的关系。如果您无法确定,我是Java的新手,并且来自Obj-C背景。他们特别提到:

除了绑定到POJO和“简单”类型外,还有另一种变体:绑定到通用(类型化)容器。这种情况由于所谓的Type Erasure(类型擦除)(Java使用它以某种向后兼容的方式实现泛型)而需要特殊处理,这使您无法使用Collection.class之类的东西(不会编译)。

因此,如果要将数据绑定到地图中,则需要使用:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });

我如何直接反序列化到ArrayList


Answers:


149

您可以使用TypeReference包装器直接反序列化为列表。示例方法:

public static <T> T fromJSON(final TypeReference<T> type,
      final String jsonPacket) {
   T data = null;

   try {
      data = new ObjectMapper().readValue(jsonPacket, type);
   } catch (Exception e) {
      // Handle the problem
   }
   return data;
}

因此用于:

final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);

TypeReference Javadoc


您的答案似乎与他们有关如何使用内置支持的信息有关TypeReference-我只是不知道如何使用...请参阅上面的编辑,以获取有关如何使用泛型的说明。
tacos_tacos_tacos 2012年

好吧,这是相关的。但这是生产中工作代码的摘录。不用担心您的mixin,只需使用我显示的代码即可(当然,请使用实际bean类的名称替换POJO)。
感知2012年

您的代码已编译,但是在尝试打印arrayList.toString()about 时遇到运行时异常NullPointerException。我猜测这可能是因为我POJO的属性不符合正确的命名约定,也就是说,整个问题是Web服务返回Prop1Member并且我的对象具有Prop1。这是我开始使用mixins的唯一真实原因,因此我不必@JsonProperty在纯对象中放入声明。
tacos_tacos_tacos 2012年

1
目视检查阵列,以确保至少返回了列表。并且,如果需要的话,还可以添加混入,它应该与TypeReference一起使用,以使所有内容都经过反序列化。
感知

2
@JsonProperty并不像人们指出的那样邪恶。很难摆脱供应商特定的注释,而该字段在当前的标准化状态(最低)下会怎样。
感知2012年

104

另一种方法是将数组用作类型,例如:

ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);

这样可以避免使用Type对象带来的麻烦,并且如果您确实需要列表,可以始终通过以下方式将数组转换为列表:

List<MyPojo> pojoList = Arrays.asList(pojos);

恕我直言,这更具可读性。

并使其成为实际列表(可以修改,请参阅的限制Arrays.asList()),然后执行以下操作:

List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));

1
可以肯定,但是由于MyPojo []。class,我不想将其泛化,因此我不想将其作为参数传递。
阿德里安·雷杰斯

我认为使用TypeFactory下一个答案中所述的方法:stackoverflow.com/a/42458104/91497是指定类型的Jackson方法。
Jmini

32

此变体看起来更加简单和优雅。

CollectionType typeReference =
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);

3

我也有同样的问题。我有一个要转换为ArrayList的json。

帐户看起来像这样。

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

以上所有类均已正确注释。我已经尝试过TypeReference>(){},但是没有用。

它给了我Arraylist,但ArrayList有一个linkedHashMap,其中包含一些包含最终值的更多链接的哈希图。

我的代码如下:

public T unmarshal(String responseXML,String c)
{
    ObjectMapper mapper = new ObjectMapper();

    AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

    mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

    mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
    try
    {
      this.targetclass = (T) mapper.readValue(responseXML,  new TypeReference<ArrayList<T>>() {});
    }
    catch (JsonParseException e)
    {
      e.printStackTrace();
    }
    catch (JsonMappingException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    return this.targetclass;
}

我终于解决了问题。我能够将Json String中的列表直接转换为ArrayList,如下所示:

JsonMarshallerUnmarshaller<T>{

     T targetClass ;

     public ArrayList<T> unmarshal(String jsonString)
     {
        ObjectMapper mapper = new ObjectMapper();

        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

        mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
        JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, targetclass.getClass()) ;
        try
        {
        Class c1 = this.targetclass.getClass() ;
        Class c2 = this.targetclass1.getClass() ;
            ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString,  type);
        return temp ;
        }
       catch (JsonParseException e)
       {
        e.printStackTrace();
       }
       catch (JsonMappingException e) {
           e.printStackTrace();
       } catch (IOException e) {
          e.printStackTrace();
       }

     return null ;
    }  

}

2

这对我有用。

@Test
public void cloneTest() {
    List<Part> parts = new ArrayList<Part>();
    Part part1 = new Part(1);
    parts.add(part1);
    Part part2 = new Part(2);
    parts.add(part2);
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(parts);

        List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
    } catch (Exception e) {
        //fail("failed.");
        e.printStackTrace();
    }

    //TODO: Assert: compare both list values.
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.