Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions gson/src/main/java/com/google/gson/Gson.java
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ public <T> T fromJson(Reader json, TypeToken<T> typeOfT)
throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = newJsonReader(json);
T object = fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
assertFullConsumption(jsonReader);
return object;
}

Expand Down Expand Up @@ -1193,11 +1193,14 @@ public <T> T fromJson(JsonElement json, TypeToken<T> typeOfT) throws JsonSyntaxE
return fromJson(new JsonTreeReader(json), typeOfT);
}

private static void assertFullConsumption(Object obj, JsonReader reader) {
private static void assertFullConsumption(JsonReader reader) {
try {
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
if (reader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("JSON document was not fully consumed.");
}
} catch (EOFException e) {
// Stream is exhausted — no trailing data. This happens when the input was empty
// or contained only whitespace, which Gson accepts for backward compatibility.
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
Expand Down
10 changes: 8 additions & 2 deletions gson/src/main/java/com/google/gson/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
Expand Down Expand Up @@ -108,8 +109,13 @@ public static JsonElement parseReader(Reader reader) throws JsonIOException, Jso
try {
JsonReader jsonReader = new JsonReader(reader);
JsonElement element = parseReader(jsonReader);
if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("Did not consume the entire document.");
try {
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("Did not consume the entire document.");
}
} catch (EOFException e) {
// Stream is exhausted — no trailing data. This happens when the input was empty
// or contained only whitespace, which Gson accepts for backward compatibility.
}
return element;
} catch (MalformedJsonException | NumberFormatException e) {
Expand Down
24 changes: 24 additions & 0 deletions gson/src/test/java/com/google/gson/GsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -637,4 +637,28 @@ public CustomClass3() {
this(NO_ARG_CONSTRUCTOR_VALUE);
}
}

/**
* Gson.fromJson should reject trailing data after a top-level JSON null, just as it does for
* non-null values. Previously, assertFullConsumption skipped the reader.peek() check when the
* deserialized object was null, silently ignoring any trailing content.
*/
@Test
public void testFromJsonRejectsTrailingDataAfterNull_String() {
Gson gson = new Gson();
// Non-null with trailing data already throws — verify that baseline
assertThrows(
JsonSyntaxException.class, () -> gson.fromJson("\"hello\" trailing", String.class));
// Null with trailing data should also throw, but previously didn't
assertThrows(JsonSyntaxException.class, () -> gson.fromJson("null trailing", String.class));
}

@Test
public void testFromJsonRejectsTrailingDataAfterNull_Reader() {
Gson gson = new Gson();
// Null with trailing data through the Reader overload
assertThrows(
JsonSyntaxException.class,
() -> gson.fromJson(new StringReader("null trailing"), String.class));
}
}
16 changes: 16 additions & 0 deletions gson/src/test/java/com/google/gson/JsonParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,20 @@ public void testStrict() {
// Original strictness was kept
assertThat(reader.getStrictness()).isEqualTo(strictness);
}

/**
* JsonParser.parseReader(Reader) should reject trailing data after a top-level JSON null, just as
* it does for non-null values. Previously, the trailing-data check was gated by
* !element.isJsonNull(), silently ignoring any content after "null".
*/
@Test
public void testParseReaderRejectsTrailingDataAfterNull() {
// Non-null with trailing data already throws — verify that baseline
assertThrows(
JsonSyntaxException.class,
() -> JsonParser.parseReader(new StringReader("\"hello\" trailing")));
// Null with trailing data should also throw, but previously didn't
assertThrows(
JsonSyntaxException.class, () -> JsonParser.parseReader(new StringReader("null trailing")));
}
}
Loading