ObjectMapper.readValues() 对错误 JSON 输入的奇怪行为

Posted

技术标签:

【中文标题】ObjectMapper.readValues() 对错误 JSON 输入的奇怪行为【英文标题】:Weird behavior of ObjectMapper.readValues() for bad JSON input 【发布时间】:2021-09-15 06:34:28 【问题描述】:

我正在开发一个经常使用 Jackson 的应用程序。为了了解readValue() 在某些极端情况下的工作原理,我设置了一个小实验。首先,一个故意为空的内部类:

static class Empty 
    @Override
    public String toString()
        return "Empty class!";
    

现在让我们设置一些打印输出:

public void testFromJsonStringBadInput() 
    String[] emptyNullOrBadJsons = "", "", "", "", "", "", "";
    Class<?>[] types = Empty.class, Object.class;
    for(String s: emptyNullOrBadJsons) 
        for(Class<?> clazz : types) 
            try 
                    System.out.println("new ObjectMapper().readValue(" + s +  ", " + clazz.getSimpleName() + ")=" + new ObjectMapper().readValue(s, clazz));
             catch(Exception exc) 
                    System.out.println("Deserialization failure for Json string: " + s + " and class: " + clazz.getSimpleName() + ". Exception: " + exc.getClass().getSimpleName() +" and message: " + exc.getMessage());
            
        
    


因此,对于一堆极端情况的 JSON,我反序列化为 EmptyObject 的实例,并打印由 readValue() 生成的对象。这是这个小代码的输出:

Deserialization failure for Json string:  and class: Empty. Exception: MismatchedInputException and message: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
Deserialization failure for Json string:  and class: Object. Exception: MismatchedInputException and message: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=
Deserialization failure for Json string:  and class: Empty. Exception: JsonEOFException and message: Unexpected end-of-input: expected close marker for Object (start marker at [Source: (String)""; line: 1, column: 1])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonEOFException and message: Unexpected end-of-input: expected close marker for Object (start marker at [Source: (String)""; line: 1, column: 1])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected character ('' (code 123)): was expecting double-quote to start field name
 at [Source: (String)""; line: 1, column: 3]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected character ('' (code 123)): was expecting double-quote to start field name
 at [Source: (String)""; line: 1, column: 3]
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=

Process finished with exit code 0

我希望在最后一个字符串"" 的所有情况下看到此输出除了。杰克逊反序列化器似乎很好地解析了这个 JSON,没有抛出异常,这对于我的自定义 Empty 类和 Object 都是成功的。怎么会?我本来希望readValue() 扔到这里。

如果它在任何方面很重要,这是我整个pom.xml 中唯一的杰克逊参考:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

【问题讨论】:

【参考方案1】:

我想我明白了。 Jackson 选择在成功的闭括号对之后不解析 JSON 的任何部分。我将以下字符串添加到正在处理的错误 JSON 数组中:

"", "", " \"obj\":", "\"name\" : \"Jason\""

完整方法:

public void testFromJsonStringBadInput() 
    String[] emptyNullOrBadJsons = "", "", "", "", "", "", "", "", "", " \"obj\":", "\"name\" : \"Jason\"";
    Class<?>[] types = Empty.class, Object.class;
    for(String s: emptyNullOrBadJsons) 
        for(Class<?> clazz : types) 
            try 
                System.out.println("new ObjectMapper().readValue(" + s +  ", " + clazz.getSimpleName() + ")=" + new ObjectMapper().readValue(s, clazz));
             catch(Exception exc) 
                System.out.println("Deserialization failure for Json string: " + s + " and class: " + clazz.getSimpleName() + ". Exception: " + exc.getClass().getSimpleName() +" and message: " + exc.getMessage());
            
        
    

输出支持了假设,Empty 不足以解析字符串" \"obj\":" "\"name\" : \"Jason\"" 的事实也反映出来:

Deserialization failure for Json string:  and class: Empty. Exception: MismatchedInputException and message: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
Deserialization failure for Json string:  and class: Object. Exception: MismatchedInputException and message: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=
Deserialization failure for Json string:  and class: Empty. Exception: JsonEOFException and message: Unexpected end-of-input: expected close marker for Object (start marker at [Source: (String)""; line: 1, column: 1])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonEOFException and message: Unexpected end-of-input: expected close marker for Object (start marker at [Source: (String)""; line: 1, column: 1])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected close marker '': expected ']' (for root starting at [Source: (String)""; line: 1, column: 0])
 at [Source: (String)""; line: 1, column: 2]
Deserialization failure for Json string:  and class: Empty. Exception: JsonParseException and message: Unexpected character ('' (code 123)): was expecting double-quote to start field name
 at [Source: (String)""; line: 1, column: 3]
Deserialization failure for Json string:  and class: Object. Exception: JsonParseException and message: Unexpected character ('' (code 123)): was expecting double-quote to start field name
 at [Source: (String)""; line: 1, column: 3]
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=
new ObjectMapper().readValue(, Empty)=Empty class!
new ObjectMapper().readValue(, Object)=
Deserialization failure for Json string:  "obj": and class: Empty. Exception: UnrecognizedPropertyException and message: Unrecognized field "obj" (class com.drfirst.gear.user.context.util.AppUtilTest$Empty), not marked as ignorable (0 known properties: ])
 at [Source: (String)" "obj":"; line: 1, column: 10] (through reference chain: com.drfirst.gear.user.context.util.AppUtilTest$Empty["obj"])
new ObjectMapper().readValue( "obj":, Object)=obj=
Deserialization failure for Json string: "name" : "Jason" and class: Empty. Exception: UnrecognizedPropertyException and message: Unrecognized field "name" (class com.drfirst.gear.user.context.util.AppUtilTest$Empty), not marked as ignorable (0 known properties: ])
 at [Source: (String)""name" : "Jason""; line: 1, column: 12] (through reference chain: com.drfirst.gear.user.context.util.AppUtilTest$Empty["name"])
new ObjectMapper().readValue("name" : "Jason", Object)=name=Jason

Process finished with exit code 0

【讨论】:

以上是关于ObjectMapper.readValues() 对错误 JSON 输入的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章