Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve location information in JsonReader exception messages #1764

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

Marcono1234
Copy link
Collaborator

@Marcono1234 Marcono1234 commented Aug 25, 2020

Based on #1743
Fixes #1564

Improves the location information shown in JsonReader exception messages and improves the tests by making them check the exception messages as well.

Improved location information:

  • Partially due to Fix JsonReader advancing before throwing exception due to malformed JSON #1743 since the position is not changed if malformed JSON is encountered
  • Unexpected token will report start of peeked token:
    Previously when the peeked token did not match the expected one, the exception message reported the location behind the token (instead of in front of it), e.g.:
    new JsonReader(new StringReader("true")).beginObject();
    // Expected BEGIN_OBJECT but was BOOLEAN at line 1 column 5 path $
  • Add location information to some exceptions which previously did not have location information
  • Don't have strict reader suggest lenient mode when that would not help:
    Previously a strict reader would suggest lenient mode even in cases where lenient mode would not be able to read the JSON either.

Previously JsonReader.doPeek() would have already advanced or modified the
state of the reader when malformed JSON was encountered and an exception
was thrown. Therefore repeatedly calling methods which peek would result
in inconsistent exceptions and could even make the JSON "valid" again by
simply advancing past the malformed JSON.

Now the state of the reader is only modified when valid JSON is encountered.
Note that there are a few remaining cases where this issue still occurs,
which will be fixed in subsequent commits.

This change required adding more JsconScope constants because if there is
enough space (or a long comment) between tokens the skipped content could
not have been stored in the buffer, e.g. `{"a":   ...     :1}`.
Here a value is expected after the `:`. However there are a lot of
whitespaces followed by a second `:` (i.e. malformed JSON).
With the previous JsonScopes it would not have been possible to represent
this state correctly. Therefore a subsequent peek would have consumed the
second `:` making the JSON "valid" again.
…scape

Previously JsonReader.nextString() and skipValue() consumed the '\' of an
escape sequence before throwing an exception for invalid escape sequences.
Therefore a subsequent method call would have read a "valid" string.

Now the stream position is only advanced when the escape sequence is valid.
Check for exception messages and make caught exception type more specific
in some cases to make sure tests do not catch wrong exception and
erroneously assume that code works as expected.

Removes JsonWriterTest.testStrictWriterDoesNotPermitMultipleTopLevelValues()
because it is the same as testMultipleTopLevelValues().
For a malformed unicode escape sequence the exception message thrown be the
method erroneously only included the first 4 chars which is `\uXX`, missing
the last 2 hex chars.
Previously when JsonReader threw an exception describing an issue with
the peeked value (e.g. it being different than the expected one) it used
the current `lineNumber` and `pos`. This resulted in confusing error
messages because both values point behind the value responsible for the
error.
For example:
  new JsonReader(new StringReader("true")).beginObject();
  // Expected BEGIN_OBJECT but was BOOLEAN at line 1 column 5 path $

With these changes the exception messages now correctly refer to the
start of the peeked value.
Adds location information to some exceptions thrown by JsonReader which
previously did not have any location information.
Previously JsonReader threw an exception when a number or keyword was
followed by a lenient non-literal. This made JsonReader consider the
complete number / keyword malformed even though only the separator is
malformed. To be consistent with EOF exceptions and exceptions for string
values, the exception is now only thrown after the number / keyword has
been consumed and when the caller tries to peek at the next JSON token.
For example:
  JsonReader reader = new JsonReader(new StringReader("[true;true]"));
  reader.beginArray();
  // Would previously already have thrown exception; with these changes
  // only trying to read value after that will throw exception
  reader.nextBoolean();

Additionally JsonReader will now complain about non-literal unquoted
name or value starts as being not a name / value instead of suggesting
making the reader lenient when that would not help, e.g.:
  JsonReader reader = new JsonReader(new StringReader("="));
  // Previously this threw exception suggesting to make reader lenient
  // However, lenient reader won't accept that JSON either
  reader.nextString();
…lues

Previously a strict JsonReader suggested enabling lenient mode for multiple
top level values even if the subsequent values would not be accepted in
lenient mode either.
All callers which previously wanted isLiteral(...) to check whether the
reader is lenient for comments are calling nextNonWhitespace(boolean)
before that, which already performs the lenient check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JsonReader throws NumberFormatException which does not contain location info
1 participant