如何使用Jackson ObjectMapper检测尾随垃圾

ver*_*ard 3 java parsing json jackson

说我上课了

class A {
    public int x;
}
Run Code Online (Sandbox Code Playgroud)

然后可以解析有效的json,如下所示:

ObjectMapper mapper = new ObjectMapper();
A a = mapper.readValue("{\"x\" : 3}", A.class);
Run Code Online (Sandbox Code Playgroud)

如果字符串包含的数据超过解析对象所需的数据,是否有办法让解析器失败?

例如,我希望以下失败(成功)

A a = mapper.readValue("{\"x\" : 3} trailing garbage", A.class);
Run Code Online (Sandbox Code Playgroud)

我尝试使用带有JsonParser.Feature.AUTO_CLOSE_SOURCE = false的InputStream并检查流是否已被完全消耗,但这不起作用:

A read(String s) throws JsonParseException, JsonMappingException, IOException {
    JsonFactory f = new MappingJsonFactory();
    f.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
    ObjectMapper mapper = new ObjectMapper(f);
    InputStream is = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
    try {
        A a = mapper.readValue(is, A.class);
        if(is.available() > 0) {
            throw new RuntimeException();
        }
        return a;
    } finally {
        is.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

那是,

read("{\"x\" : 3} trailing garbage");
Run Code Online (Sandbox Code Playgroud)

仍然成功,可能是因为解析器从流中消耗的数量超过了严格必要的数量.

一个有效的解决方案是在从字符串中删除最后一个字符串时验证解析失败:

A read(String s) throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    A a = mapper.readValue(s, A.class);

    if (s.length() > 0) {
        try {
            mapper.readValue(s.substring(0, s.length()-1), A.class);
            throw new RuntimeException();
        } catch (JsonParseException e) {
        }
    }

    return a;
}
Run Code Online (Sandbox Code Playgroud)

但我正在寻找更有效的解决方案.

Sta*_*Man 6

要做的主要是创建JsonParser第一个,单独,然后调用ObjectMapper.readValue()传递该解析器,然后THEN nextToken()再次调用并验证它返回null(而不是非null值,或抛出异常).

所以,像

JsonParser jp = mapper.getFactory().createParser(jsonSource);
try {
    Value v = mapper.readValue(jp, Value.class);
    if (jp.nextToken() != null) {
        //throw some exception: trailing garbage detected
    }
    return v;
} finally {
    jp.close();
}
Run Code Online (Sandbox Code Playgroud)

注意:这是针对Jackson 2.x. 对于Jackson 1.x,请使用getJsonFactory().createJsonParser()而不是getFactory().createParser().


anr*_*nre 6

截至Jackson版本2.9,现在有DeserializationFeature.FAIL_ON_TRAILING_TOKENS可用于实现:

ObjectMapper objectMapper =
        new ObjectMapper().enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
Run Code Online (Sandbox Code Playgroud)

请参阅 https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9https://medium.com/@cowtowncoder/jackson-2-9-features-b2a19029e9ff