The formatting of JSON content has to fulfill some specific rules to be compliant with the standard. The standard is described in the RFC4627 specification. It lays the foundation on how keys and values are separated, how arrays are structured and so on. In this blog post we'll explore how Gson's relationship is with the JSON specification.
Of course, this will not be the only post in our Gson series. If you're interested in the other topics, check out our series outline:
Gson Series Overview
- Mapping of Enums
- Mapping of Circular References
- Custom Serialization for Simplification (Part 1)
- Changing the Default Serialization with Custom Serialization (Part 2)
- Custom Deserialization Basics
- Custom Instance Creator
- Customizing (De)Serialization via @JsonAdapter
- Custom Deserialization for Calculated Fields
- On-The-Fly-Parsing With Streams
- ProGuard Configuration
Lenient by Default?
First of all, when Gson serializes Java objects it'll create a JSON, which is 100% compliant with the standard. The interesting part is how Gson behaves during deserialization!
Internally, Gson utilizes a JsonReader class. That class has an option to be lenient or not. By default it's not lenient, which means that it only accepts compliant JSON input. If the JSON violates one of the structure rules, the
JsonReader and consequently Gson will throw an exception. However, the
JsonReader has the optional setting to be lenient. Then, and only then, it'll swallow certain violations and try it's best to read even a questionably formatted JSON.
Let's cite the documentation of some non-standard JSON elements:
- Streams that start with the non-execute prefix, ")]}'\n".
- Streams that include multiple top-level values. With strict parsing, each stream must contain exactly one top-level value.
- Top-level values of any type. With strict parsing, the top-level value must be an object or an array.
- Numbers may be NaNs or infinities.
- End of line comments starting with // or # and ending with a newline character.
- C-style comments starting with /* and ending with */. Such comments may not be nested.
- Names that are unquoted or 'single quoted'.
- Strings that are unquoted or 'single quoted'.
- Array elements separated by ; instead of ,.
- Unnecessary array separators. These are interpreted as if null was the omitted value.
- Names and values separated by = or => instead of :.
- Name/value pairs separated by ; instead of ,.
How all of this affect your work with Gson? Theoretically, Gson (unlike the
JsonReader) is already lenient by default. So usually you shouldn't need to enable it, if your JSONs are not correct. Unfortunately, there seems to be some confusion how Gson exactly behaves regarding this issue. We'll update you as things go along.
What you've to remember is that Gson has the option to be more forgiving when it comes to JSON deserialization. If you want to enable it, use the
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setLenient(); Gson gson = gsonBuilder.create();
Making your Gson instance lenient can help with some structural issues. Nevertheless, there is only so much the lenient option can do. If the violations go beyond of once of the examples we've shown you above, Gson will throw a
MalformedJsonException. If you run into one of those, you might want to check your JSON and its structural validity. In almost all cases there is the root cause of your problem.
We recommend to use a tool like JSONLint to validate your JSON.
In this blog post, you've learned what lenient in the context of JSON deserialization means. You're also aware that Gson's behavior isn't 100% clear on this issue. Theoretically, Gson should be lenient by default. If you require it to be lenient, we recommend setting it via the
GsonBuilder just in case future updates will change the default behavior.
In the next blog post, we'll look at Gson's serialization of floats!
If you've feedback or a question, let us know in the comments or on twitter @futurestud_io.
Make it rock & enjoy coding!