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

Making Gson.fromJson(Reader, Class) return after one JSON value is read #1733

Open
TaylanUB opened this issue Jul 7, 2020 · 4 comments
Open

Comments

@TaylanUB
Copy link

TaylanUB commented Jul 7, 2020

When you pass a Reader to Gson.fromJson(), it seems to keep reading data until EOF or a syntax error. Perhaps this is desired in some scenarios, like strict error checking to ensure there's no superfluous data after the JSON value, but what if you want to read a JSON value that's just part of a longer-running stream?

It would be great if, as an optional setting, one could instruct Gson to stop reading from a reader after the end of a value is reached.

For all value types except Number, the end of the value is unambiguous: in case of an Array the closing square bracket, in case of an Object the closing curly brace, in case of a string the closing double quote, in case of booleans and null the end of the corresponding character string.

Numbers don't have an obvious end. Theoretically one could stop reading when the addition of the next digit would cause an overflow, but that might mask some actual errors. I have no opinion on how exactly the behavior should be because I don't think I'll ever need to read bare JSON numbers over a continuous stream; one can always wrap them in a one-element array or a trivial object like {"value":12345}.

Ensuring proper behavior would probably require the use of mark() and reset() on the reader. Once Gson has read a whole chunk of characters, it might realize that it's already read beyond the end of the JSON value. In that case it would need to count the number of characters that belong to the JSON value, reset() to before the last read() operation, and re-read only as many characters as it knows there exist until the end of the JSON value.

Thoughts?

@lyubomyr-shaydariv
Copy link
Contributor

Not sure but are you probably talking about something like:

final Gson gson = new Gson();
final JsonReader jsonReader = new JsonReader(new StringReader("1 2 3 4"));
jsonReader.setLenient(true);
while ( jsonReader.peek() != JsonToken.END_DOCUMENT && jsonReader.hasNext() ) {
	final int i = gson.fromJson(jsonReader, int.class);
	System.out.println(i);
}

? This seems to fit

what if you want to read a JSON value that's just part of a longer-running stream

instruct Gson to stop reading from a reader after the end of a value is reached

read bare JSON numbers over a continuous stream; one can always wrap them in a one-element array or a trivial object like {"value":12345}

if combined, but does not seem to fit mark() and reset() though.

@TaylanUB
Copy link
Author

@lyubomyr-shaydariv I don't think this does what I want. The main problem is that .fromJson() as well as .peek() might block even if a whole JSON value is available in the stream, because they will wait for EOF or another token.

I'd also rather not use lenient parsing for the values I read.

@blerner
Copy link

blerner commented Dec 12, 2024

To follow up on @TaylanUB 's comment, currently LENIENT mode couples together "can read multiple top-level values" with "can read unquoted/single-quoted strings, comments, and various other formatting exceptions." I understand the appeal of a simpler API with .setStrictness(STRICT | LENIENT | LEGACY_STRICT), but given GsonBuilder already has so many configurable options, it seems surprising to me (and also computationally troublesome at times) to tether together "how many values are supported?" with "what is the valid syntax of each value?"

Perhaps adding another option, .permitMultipleTopLevelValues(boolean allowed) could permit configuring this ability independently of lenient per-item parsing?

@Marcono1234
Copy link
Collaborator

Slightly related to #2769

Related to #1180; you currently have to use a single JsonReader (and make it lenient) because it buffers data internally, so using a separate JsonReader object for each top-level value is not possible.

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

No branches or pull requests

4 participants