How to detect trash using Jackson ObjectMapper

Say I have a class

class A {
    public int x;
}

Then, valid json can be parsed as follows:

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

Is there a way for the parser to fail if the string contains more data than is needed to parse the object?

For example, I would like to accomplish the following (which is successful)

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

I tried it using InputStream with JsonParser.Feature.AUTO_CLOSE_SOURCE = false and checking if the stream was completely consumed, but this does not work:

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

those.

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

still succeeds, perhaps because the parser consumes more from the stream than necessary.

One solution that works is to verify that the parsing does not work when discarding the last character from a 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 am looking for a more effective solution.

+3
3

, JsonParser , , ObjectMapper.readValue(), , THEN nextToken() , null ( throw ).

, -

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().

+6

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.9 https://medium.com/@cowtowncoder/jackson-2-9-features-b2a19029e9ff

+3

You might have something like below. Basically a loop through the tokens in front of you readValue. JsonParser # nextToken () confirms that your string is proper 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)
0
source

All Articles