Skip to content

MappingIterator should fail on trailing tokens after wrapper Array if FAIL_ON_TRAILING_TOKENS enabled #6334

Open

Description

@cowtowncoder

Description

When MappingIterator reads values from within a root-level wrapper Array (that is, ObjectReader.readValues() for a managed parser, or a caller that clears the leading START_ARRAY), iteration ends at the closing END_ARRAY, and any content after it is silently ignored -- even if DeserializationFeature.FAIL_ON_TRAILING_TOKENS is enabled (which is the default in 3.x).

This is a re-file, with a specific ask, of the "trailing tokens" part of #3228, where checking this for the "from within array" case was considered legitimate.

Version

3.3.0-SNAPSHOT (same behavior in 2.x when feature is enabled)

Reproduction

record Point(int x, int y) { }

ObjectMapper m = JsonMapper.builder()
        .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) // default in 3.x anyway
        .build();
for (String json : new String[] {
        "[{\"x\":1,\"y\":2}] garbage",
        "[{\"x\":1,\"y\":2}][{\"x\":3,\"y\":4}]" }) {
    try (MappingIterator<Point> it = m.readerFor(Point.class)
            .readValues(new ByteArrayInputStream(json.getBytes()))) {
        System.out.println(json + " -> " + it.readAll());
    }
}

Output:

[{"x":1,"y":2}] garbage -> [Point[x=1, y=2]]
[{"x":1,"y":2}][{"x":3,"y":4}] -> [Point[x=1, y=2]]

In both cases no exception is thrown: the trailing garbage, or the whole second Array, is dropped without notice.

Expected behavior

If FAIL_ON_TRAILING_TOKENS is enabled, then when hasNextValue() reaches the END_ARRAY of the wrapper Array, MappingIterator should check that no more tokens follow (_parser.nextToken() == null), and report the problem via DeserializationContext.reportTrailingTokens() otherwise -- the same check readValue() does.

The check is only relevant for the wrapper Array case: for a non-wrapped sequence of root-level values, iteration already continues until EOF.

Context

Found via jackson-jakarta-rs-providers#69 (PR #70): when that provider unwraps a root-level Array for a MappingIterator<T> endpoint parameter, content after the Array is silently ignored, even though the provider's READ_FULL_STREAM feature (enabled by default) is implemented by enabling FAIL_ON_TRAILING_TOKENS. Fixing this in MappingIterator would cover the provider without it having to duplicate the logic.

Compatibility note

Since FAIL_ON_TRAILING_TOKENS defaults to true in 3.x, this would change behavior for any readValues() user with content after a wrapper Array: such content would now fail instead of being ignored. This seems correct (it is what the feature promises), but may warrant a mention in release notes; it should probably go into 3.x minor (not patch) version.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions