【问题标题】:How to detect trailing garbage using Jackson ObjectMapper如何使用 Jackson ObjectMapper 检测尾随垃圾
【发布时间】:2014-09-23 19:27:01
【问题描述】:

假设我有一堂课

class A {
    public int x;
}

那么可以解析出一个有效的json如下:

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

如果字符串包含的数据多于解析对象所需的数据,有没有办法让解析器失败?

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

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

我尝试使用带有 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();
    }
}

也就是说,

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

仍然成功,可能是因为解析器从流中消耗的内容超出了严格必要的范围。

一种可行的解决方案是验证从字符串中删除最后一个字符时解析是否失败:

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

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

【问题讨论】:

  • 解决方案对您有用吗?

标签: java json parsing jackson


【解决方案1】:

从 Jackson 2.9 版开始,现在有 DeserializationFeature.FAIL_ON_TRAILING_TOKENS 可用于实现这一目标:

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

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

【讨论】:

    【解决方案2】:

    要做的主要事情是首先单独创建一个JsonParser,然后调用ObjectMapper.readValue()传递该解析器,然后再次调用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();
    }
    

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

    【讨论】:

      【解决方案3】:

      你可以有类似下面的东西。 基本上在readValue 之前遍历令牌。 JsonParser#nextToken() 验证您的字符串是否为正确的 JSON。

      代码如下:

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

      控制台输出:

      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)
      

      【讨论】:

      • 感谢您的回答,这确实有效。我接受了另一个使用相同技术但只需要扫描输入一次的答案。
      猜你喜欢
      • 2016-05-07
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      相关资源
      最近更新 更多