简体   繁体   English

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

[英]How to detect trailing garbage using Jackson ObjectMapper

Say I have a class 说我上课了

class A {
    public int x;
}

Then a valid json can be parsed as follows: 然后可以解析有效的json,如下所示:

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

Is there a way to have the parser fail if the string contains more data than necessary to parse the object? 如果字符串包含的数据超过解析对象所需的数据,是否有办法让解析器失败?

For example I would like the following to fail (which succeeds) 例如,我希望以下失败(成功)

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

I tried it using an InputStream with JsonParser.Feature.AUTO_CLOSE_SOURCE=false and checking whether the stream has been consumed completely, but that does not work: 我尝试使用带有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();
    }
}

that is, 那是,

read("{\"x\" : 3} trailing garbage");

still succeeds, probably because the parser consumes more from the stream than strictly necessary. 仍然成功,可能是因为解析器从流中消耗的数量超过了严格必要的数量。

One solution that works is to verify that the parsing fails when dropping the last charachter from the string: 一个有效的解决方案是在从字符串中删除最后一个字符时验证解析失败:

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

but I'm looking for a more efficient solution. 但我正在寻找更有效的解决方案。

The main thing to do is to create a JsonParser first, separately, then call ObjectMapper.readValue() passing that parser, and THEN call nextToken() once more and verify it returns null (instead of non-null value, or throw exception). 要做的主要是首先单独创建一个JsonParser ,然后调用ObjectMapper.readValue()传递该解析器,然后THEN再次调用nextToken()并验证它返回null(而不是非null值,或抛出异常) 。

So, something like 所以,像

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

Note: This is for Jackson 2.x. 注意:这是针对Jackson 2.x. For Jackson 1.x, use getJsonFactory().createJsonParser() instead of getFactory().createParser() . 对于Jackson 1.x,使用getJsonFactory().createJsonParser()而不是getFactory().createParser()

As of Jackson version 2.9, there is now DeserializationFeature.FAIL_ON_TRAILING_TOKENS which can be used to achieve that: 截至Jackson版本2.9,现在有DeserializationFeature.FAIL_ON_TRAILING_TOKENS可用于实现:

ObjectMapper objectMapper =
        new ObjectMapper().enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);

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

You can have something like below. 你可以有类似下面的东西。 Basically loop through the tokens before you readValue . readValue之前,基本上循环遍历标记。 JsonParser#nextToken() validates if your String is a proper JSON. JsonParser#nextToken()验证您的String是否是正确的JSON。

Here is the code: 这是代码:

public static void main(String[] args) throws JsonParseException, IOException  {

        ObjectMapper mapper = new ObjectMapper();

        String str = "{\"x\" : 3} garbage";

        JsonParser x = mapper.getJsonFactory().createJsonParser(str);
        while(x.nextToken()!=null){

        }
    A a =   mapper.readValue(str, A.class);

        System.out.println(a);
    }

console output: 控制台输出:

Exception in thread "main" org.codehaus.jackson.JsonParseException: Unexpected character ('g' (code 103)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: java.io.StringReader@65faba46; line: 1, column: 12]
    at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1432)
    at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:385)
    at org.codehaus.jackson.impl.JsonParserMinimalBase._reportUnexpectedChar(JsonParserMinimalBase.java:306)
    at org.codehaus.jackson.impl.ReaderBasedParser._handleUnexpectedValue(ReaderBasedParser.java:1192)
    at org.codehaus.jackson.impl.ReaderBasedParser.nextToken(ReaderBasedParser.java:479)
    at example.JsonParse.main(JsonParse.java:21)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM