Skip to content

Commit

Permalink
Merge branch 'main' into fix-proguard-rules
Browse files Browse the repository at this point in the history
  • Loading branch information
sgjesse committed Aug 10, 2023
2 parents c34126b + cdbbee4 commit af98d32
Show file tree
Hide file tree
Showing 35 changed files with 1,012 additions and 585 deletions.
11 changes: 7 additions & 4 deletions Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ For example, let's assume you want to deserialize the following JSON data:
}
```

This will fail with an exception similar to this one: `MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 5 column 4 path $.languages[2]`
This will fail with an exception similar to this one: `MalformedJsonException: Use JsonReader.setStrictness(Strictness.LENIENT) to accept malformed JSON at line 5 column 4 path $.languages[2]`
The problem here is the trailing comma (`,`) after `"French"`, trailing commas are not allowed by the JSON specification. The location information "line 5 column 4" points to the `]` in the JSON data (with some slight inaccuracies) because Gson expected another value after `,` instead of the closing `]`. The JSONPath `$.languages[2]` in the exception message also points there: `$.` refers to the root object, `languages` refers to its member of that name and `[2]` refers to the (missing) third value in the JSON array value of that member (numbering starts at 0, so it is `[2]` instead of `[3]`).
The proper solution here is to fix the malformed JSON data.

Expand All @@ -147,9 +147,12 @@ To spot syntax errors in the JSON data easily you can open it in an editor with

**Reason:** Due to legacy reasons Gson performs parsing by default in lenient mode

**Solution:** See [`Gson` class documentation](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/Gson.html#default-lenient) section "Lenient JSON handling"

Note: Even in non-lenient mode Gson deviates slightly from the JSON specification, see [`JsonReader.setLenient`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/stream/JsonReader.html#setLenient(boolean)) for more details.
**Solution:** If you are using Gson 2.11.0 or newer, call [`GsonBuilder.setStrictness`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html#setStrictness(com.google.gson.Strictness)),
[`JsonReader.setStrictness`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/stream/JsonReader.html#setStrictness(com.google.gson.Strictness))
and [`JsonWriter.setStrictness`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/stream/JsonWriter.html#setStrictness(com.google.gson.Strictness))
with `Strictness.STRICT` to overwrite the default lenient behavior of `Gson` and make these classes strictly adhere to the JSON specification.
Otherwise if you are using an older Gson version, see the [`Gson` class documentation](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/Gson.html#default-lenient)
section "JSON Strictness handling" for alternative solutions.

## <a id="unexpected-json-structure"></a> `IllegalStateException`: "Expected ... but was ..."

Expand Down
4 changes: 2 additions & 2 deletions gson/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>2.20.0</version>
<version>2.21.1</version>
</dependency>

<dependency>
Expand All @@ -62,7 +62,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>32.1.1-jre</version>
<version>32.1.2-jre</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
127 changes: 91 additions & 36 deletions gson/src/main/java/com/google/gson/Gson.java

Large diffs are not rendered by default.

57 changes: 42 additions & 15 deletions gson/src/main/java/com/google/gson/GsonBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@
import static com.google.gson.Gson.DEFAULT_ESCAPE_HTML;
import static com.google.gson.Gson.DEFAULT_FORMATTING_STYLE;
import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
import static com.google.gson.Gson.DEFAULT_LENIENT;
import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
import static com.google.gson.Gson.DEFAULT_STRICTNESS;
import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe;
import com.google.gson.annotations.Since;
import com.google.gson.annotations.Until;
import com.google.gson.internal.$Gson$Preconditions;
Expand Down Expand Up @@ -71,12 +72,16 @@
* .create();
* </pre>
*
* <p>NOTES:
* <p>Notes:
* <ul>
* <li> the order of invocation of configuration methods does not matter.</li>
* <li> The default serialization of {@link Date} and its subclasses in Gson does
* <li>The order of invocation of configuration methods does not matter.</li>
* <li>The default serialization of {@link Date} and its subclasses in Gson does
* not contain time-zone information. So, if you are using date/time instances,
* use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
* <li>By default no explicit {@link Strictness} is set; some of the {@link Gson} methods
* behave as if {@link Strictness#LEGACY_STRICT} was used whereas others behave as
* if {@link Strictness#LENIENT} was used. Prefer explicitly setting a strictness
* with {@link #setStrictness(Strictness)} to avoid this legacy behavior.
* </ul>
*
* @author Inderjeet Singh
Expand All @@ -100,7 +105,7 @@ public final class GsonBuilder {
private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
private FormattingStyle formattingStyle = DEFAULT_FORMATTING_STYLE;
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
private boolean lenient = DEFAULT_LENIENT;
private Strictness strictness = DEFAULT_STRICTNESS;
private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
Expand Down Expand Up @@ -130,7 +135,7 @@ public GsonBuilder() {
this.generateNonExecutableJson = gson.generateNonExecutableJson;
this.escapeHtmlChars = gson.htmlSafe;
this.formattingStyle = gson.formattingStyle;
this.lenient = gson.lenient;
this.strictness = gson.strictness;
this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
this.longSerializationPolicy = gson.longSerializationPolicy;
this.datePattern = gson.datePattern;
Expand Down Expand Up @@ -521,18 +526,40 @@ public GsonBuilder setFormattingStyle(FormattingStyle formattingStyle) {
}

/**
* Configures Gson to allow JSON data which does not strictly comply with the JSON specification.
* Sets the strictness of this builder to {@link Strictness#LENIENT}.
*
* <p>Note: Due to legacy reasons most methods of Gson are always lenient, regardless of
* whether this builder method is used.
* @deprecated This method is equivalent to calling {@link #setStrictness(Strictness)} with
* {@link Strictness#LENIENT}: {@code setStrictness(Strictness.LENIENT)}
*
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @see JsonReader#setLenient(boolean)
* @see JsonWriter#setLenient(boolean)
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern.
* @see JsonReader#setStrictness(Strictness)
* @see JsonWriter#setStrictness(Strictness)
* @see #setStrictness(Strictness)
*/
@Deprecated
@InlineMe(replacement = "this.setStrictness(Strictness.LENIENT)", imports = "com.google.gson.Strictness")
@CanIgnoreReturnValue
public GsonBuilder setLenient() {
lenient = true;
return setStrictness(Strictness.LENIENT);
}

/**
* Sets the strictness of this builder to the provided parameter.
*
* <p>This changes how strict the
* <a href="https://www.ietf.org/rfc/rfc8259.txt">RFC 8259 JSON specification</a> is enforced when parsing or
* writing JSON. For details on this, refer to {@link JsonReader#setStrictness(Strictness)} and
* {@link JsonWriter#setStrictness(Strictness)}.</p>
*
* @param strictness the new strictness mode. May not be {@code null}.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern.
* @see JsonReader#setStrictness(Strictness)
* @see JsonWriter#setStrictness(Strictness)
* @since $next-version$
*/
@CanIgnoreReturnValue
public GsonBuilder setStrictness(Strictness strictness) {
this.strictness = Objects.requireNonNull(strictness);
return this;
}

Expand Down Expand Up @@ -711,7 +738,7 @@ public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAd
}

/**
* Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
* Section 6 of <a href="https://www.ietf.org/rfc/rfc8259.txt">JSON specification</a> disallows
* special double values (NaN, Infinity, -Infinity). However,
* <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
* specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
Expand Down Expand Up @@ -804,7 +831,7 @@ public Gson create() {

return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators),
serializeNulls, complexMapKeySerialization,
generateNonExecutableJson, escapeHtmlChars, formattingStyle, lenient,
generateNonExecutableJson, escapeHtmlChars, formattingStyle, strictness,
serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories),
new ArrayList<>(this.hierarchyFactories), factories,
Expand Down
3 changes: 2 additions & 1 deletion gson/src/main/java/com/google/gson/JsonElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ public String toString() {
try {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setLenient(true);
// Make writer lenient because toString() must not fail, even if for example JsonPrimitive contains NaN
jsonWriter.setStrictness(Strictness.LENIENT);
Streams.write(this, jsonWriter);
return stringWriter.toString();
} catch (IOException e) {
Expand Down
14 changes: 7 additions & 7 deletions gson/src/main/java/com/google/gson/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public JsonParser() {}
* An exception is thrown if the JSON string has multiple top-level JSON elements,
* or if there is trailing data.
*
* <p>The JSON string is parsed in {@linkplain JsonReader#setLenient(boolean) lenient mode}.
* <p>The JSON string is parsed in {@linkplain JsonReader#setStrictness(Strictness) lenient mode}.
*
* @param json JSON text
* @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
Expand All @@ -57,7 +57,7 @@ public static JsonElement parseString(String json) throws JsonSyntaxException {
* An exception is thrown if the JSON string has multiple top-level JSON elements,
* or if there is trailing data.
*
* <p>The JSON data is parsed in {@linkplain JsonReader#setLenient(boolean) lenient mode}.
* <p>The JSON data is parsed in {@linkplain JsonReader#setStrictness(Strictness) lenient mode}.
*
* @param reader JSON text
* @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
Expand Down Expand Up @@ -87,8 +87,8 @@ public static JsonElement parseReader(Reader reader) throws JsonIOException, Jso
* Unlike the other {@code parse} methods, no exception is thrown if the JSON data has
* multiple top-level JSON elements, or if there is trailing data.
*
* <p>The JSON data is parsed in {@linkplain JsonReader#setLenient(boolean) lenient mode},
* regardless of the lenient mode setting of the provided reader. The lenient mode setting
* <p>The JSON data is parsed in {@linkplain JsonReader#setStrictness(Strictness) lenient mode},
* regardless of the strictness setting of the provided reader. The strictness setting
* of the reader is restored once this method returns.
*
* @throws JsonParseException if there is an IOException or if the specified
Expand All @@ -97,16 +97,16 @@ public static JsonElement parseReader(Reader reader) throws JsonIOException, Jso
*/
public static JsonElement parseReader(JsonReader reader)
throws JsonIOException, JsonSyntaxException {
boolean lenient = reader.isLenient();
reader.setLenient(true);
Strictness strictness = reader.getStrictness();
reader.setStrictness(Strictness.LENIENT);
try {
return Streams.parse(reader);
} catch (StackOverflowError e) {
throw new JsonParseException("Failed parsing JSON source: " + reader + " to Json", e);
} catch (OutOfMemoryError e) {
throw new JsonParseException("Failed parsing JSON source: " + reader + " to Json", e);
} finally {
reader.setLenient(lenient);
reader.setStrictness(strictness);
}
}

Expand Down
4 changes: 2 additions & 2 deletions gson/src/main/java/com/google/gson/JsonStreamParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
/**
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously. The JSON data is parsed in lenient mode, see also
* {@link JsonReader#setLenient(boolean)}.
* {@link JsonReader#setStrictness(Strictness)}.
*
* <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
* properly use this class across multiple threads, you will need to add some external
Expand Down Expand Up @@ -66,7 +66,7 @@ public JsonStreamParser(String json) {
*/
public JsonStreamParser(Reader reader) {
parser = new JsonReader(reader);
parser.setLenient(true);
parser.setStrictness(Strictness.LENIENT);
lock = new Object();
}

Expand Down
29 changes: 29 additions & 0 deletions gson/src/main/java/com/google/gson/Strictness.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.google.gson;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

/**
* Modes that indicate how strictly a JSON {@linkplain JsonReader reader} or
* {@linkplain JsonWriter writer} follows the syntax laid out in the
* <a href="https://www.ietf.org/rfc/rfc8259.txt">RFC 8259 JSON specification</a>.
*
* <p>You can look at {@link JsonReader#setStrictness(Strictness)} to see how the strictness
* affects the {@link JsonReader} and you can look at
* {@link JsonWriter#setStrictness(Strictness)} to see how the strictness
* affects the {@link JsonWriter}.</p>
*
* @see JsonReader#setStrictness(Strictness)
* @see JsonWriter#setStrictness(Strictness)
* @since $next-version$
*/
public enum Strictness {
/** Allow large deviations from the JSON specification. */
LENIENT,

/** Allow certain small deviations from the JSON specification for legacy reasons. */
LEGACY_STRICT,

/** Strict compliance with the JSON specification. */
STRICT
}
Loading

0 comments on commit af98d32

Please sign in to comment.