Java Jackson:如何反序列化JSON数组中的空元素

Java Jackson:如何反序列化JSON数组中的空元素,java,json,jackson,deserialization,pojo,Java,Json,Jackson,Deserialization,Pojo,编辑:根据你们中一些人的要求,我发布了我的真实数据结构和类。我没能让你更容易理解这个问题 我在解决JacksonnullJSON数组元素时遇到了一个问题,最后出现了一个异常,我将在本文稍后报告 我有一个来自第三方提供商的冗长JSON字符串: [ null, null, [ { "t" : { "id" : 0, "it" : "Attuazione" }, "c" : "DM.10.0.2", "

编辑:根据你们中一些人的要求,我发布了我的真实数据结构和类。我没能让你更容易理解这个问题

我在解决Jackson
null
JSON数组元素时遇到了一个问题,最后出现了一个异常,我将在本文稍后报告

我有一个来自第三方提供商的冗长JSON字符串:

[
  null,
  null,
  [
    {
      "t" : {
        "id" : 0,
        "it" : "Attuazione"
      },
      "c" : "DM.10.0.2",
      "l" : "Macro 2",
      "v0" : 0,
      "scid" : "1",
      "m" : "10",
      "sam" : 0,
      "v1" : 100,
      "smcm" : true,
      "w" : "OD.10.4",
      "st" : {
        "auto_formula" : {
          "ia" : "($x > 0 ? 1 : 0)",
          "id" : "($x > 0 ? 1 : 0)",
          "bit" : "($x > 0 ? 1 : 0)",
          "oa" : "($x > 0 ? 1 : 0)",
          "od" : "($x > 0 ? 1 : 0)",
          "dm" : "($x > 0 ? 1 : 0)"
        },
        "id" : 0,
        "css_rule" : "containerTypeOnOff",
        "default_measure_unit" : null,
        "it" : "On \/ Off",
        "widget" : {
          "id" : 0,
          "caption" : {
            "it" : "Etichetta di testo"
          }
        }
      }
    }
  ],
  null,
  null,
  null,
  null,
  null
]
我的Java类集合如下所示

这是最外面的容器:

public class TinyMap {
    ArrayList<TinyMapModule> modules;

    public TinyMap() { ...  }

    public ArrayList<TinyMapModule> getModules() { ... }

    /**
     * @param modules the modules to set
     */
    @SuppressWarnings("unchecked")
    public void setModules(ArrayList<TinyMapModule> modules) { ... }

    public void appendNewMacro(TinyMapModule m) { ... }

}
public class TinyMapModule {
    private ArrayList<TinyMapMacro> macros;

    /**
     * C'tor 
     */
    public TinyMapModule() { ... }

    /**
     * @return ArrayList<TinyMapMacro> 
     */
    public ArrayList<TinyMapMacro> getMacros() { ... }

    /**
     * @param macros the macros to set
     */
    @SuppressWarnings("unchecked")
    public void setMacros(ArrayList<TinyMapMacro> macros) { ... }

}
最后,这是我的反序列化代码:

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
ObjectReader reader = mapper.reader(TinyMapModule.class);
try {
    logger.info("Instantiating ObjectMapper");
    TinyMap tm = new TinyMap();
    tm.buildTinyMap(reader.readValues(jsonString.replaceAll("null", "[{\"name\":\"\"}]")));
    for (int i = 0; i < tm.getModules().size(); i++) {
        if (tm.getModules().get(i) == null) 
            continue;
        for (int j = 0; j < tm.getModules().get(i).getMacros().size(); j++) {
            if (tm.getModules().get(i).getMacros().get(j) == null) 
                continue;
            System.out.println(String.format("c: %s", tm.getModules().get(i).getMacros().get(i).getC()));
            System.out.println(String.format("l: %s", tm.getModules().get(i).getMacros().get(i).getL()));
            System.out.println(String.format("m: %s", tm.getModules().get(i).getMacros().get(i).getM()));
            System.out.println(String.format("t.id: %d", tm.getModules().get(i).getMacros().get(i).getTypeId()));
            System.out.println(String.format("t.it: %s", tm.getModules().get(i).getMacros().get(i).getLocalizedTypeString()));
            System.out.println(String.format("w: %s", tm.getModules().get(i).getMacros().get(i).getW()));
        }
    }
    logger.info("Execution terminated");
} 
... 
我已经读了很多关于Jackson注释、自定义反序列化程序等的内容,但我想到的唯一解决方案似乎是将
TinyMap.modules
成员从
ArrayList
转换为
ArrayList
,并使用自定义反序列化程序处理NullType对象

通过这个选择(如果可行的话,因为我还没有测试它),我将失去
TinyMap.modules
成员的语义值,我也不会被迫这么做

是否有其他方法可以解决空元素问题

编辑:


我可以在这个结构中保留非空对象的顺序位置,这一点很重要,因此我至少应该用可用作占位符的东西替换空元素。

在示例JSON中,您仍然只显示
theBeans
属性,而不是完整的
MyContainer
对象。您的错误听起来像是在试图将给定的JSON解析为
MyContainer

当然,您可以发布完整的JSON对象和反序列化代码吗


Jackson对空POJO的理解很好。

这里的问题是我在使用Jackson时造成了很多混乱

我通过阅读理解了它

正如斯塔克斯曼在评论中所建议的那样,我试图将一个集合反序列化为它不是的东西


感谢编程人员Bruce提供了有用且清晰的文章。

我不知道这是否有用,但您发布的JSON字符串不是有效的JSON。@lrsjng:你说得对,我将修复它。嗯,它仍然不是有效的JSON。。唯一的机会是将外部的花括号改为
[
]
,使其成为一个数组,因为内容没有键值,但我想这只是一个示例,所以JSON格式在这里不是问题?@lrsjng啊,你显然是对的!!!我累了,因为我已经为这件事烦了好几个小时了。谢谢你的耐心。你是对的,这是一个例子,JSON表单不是问题。我一回到办公室就会把一切都发出去。同时,我试图将整个JSON数组映射为MyContainer对象。错了吗?我在其他JSON数组结构(其中没有空元素)中尝试了它,效果非常好。我发布了所有Java类、反序列化代码和真正的JSON结构。
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
ObjectReader reader = mapper.reader(TinyMapModule.class);
try {
    logger.info("Instantiating ObjectMapper");
    TinyMap tm = new TinyMap();
    tm.buildTinyMap(reader.readValues(jsonString.replaceAll("null", "[{\"name\":\"\"}]")));
    for (int i = 0; i < tm.getModules().size(); i++) {
        if (tm.getModules().get(i) == null) 
            continue;
        for (int j = 0; j < tm.getModules().get(i).getMacros().size(); j++) {
            if (tm.getModules().get(i).getMacros().get(j) == null) 
                continue;
            System.out.println(String.format("c: %s", tm.getModules().get(i).getMacros().get(i).getC()));
            System.out.println(String.format("l: %s", tm.getModules().get(i).getMacros().get(i).getL()));
            System.out.println(String.format("m: %s", tm.getModules().get(i).getMacros().get(i).getM()));
            System.out.println(String.format("t.id: %d", tm.getModules().get(i).getMacros().get(i).getTypeId()));
            System.out.println(String.format("t.it: %s", tm.getModules().get(i).getMacros().get(i).getLocalizedTypeString()));
            System.out.println(String.format("w: %s", tm.getModules().get(i).getMacros().get(i).getW()));
        }
    }
    logger.info("Execution terminated");
} 
... 
Exception in thread "main" com.fasterxml.jackson.databind.RuntimeJsonMappingException: Can not deserialize instance of it.asystelsrl.hcsbridge.communication.TinyMapModule out of START_ARRAY token
 at [Source: java.io.StringReader@3c50507; line: 1, column: 2]
    at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:122)
    at it.asystelsrl.hcsbridge.communication.TinyMap.buildTinyMap(TinyMap.java:47)
    at it.asystelsrl.hcsbridge.tests.TestTinyMap.main(TestTinyMap.java:69)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of it.asystelsrl.hcsbridge.communication.TinyMapModule out of START_ARRAY token
 at [Source: java.io.StringReader@3c50507; line: 1, column: 2]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:599)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:593)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromArray(BeanDeserializer.java:531)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:141)
    at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:188)
    at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:120)
    ... 2 more