GsonFactory keeps parsing when a JSON field has the wrong type
Gson 解析容错框架,愿从此再无 Json 解析报错
At a glance
- What is it?
- GsonFactory is an Android library that wraps Gson with fault tolerant parsing, so a field of the wrong type is skipped or converted instead of throwing, and Kotlin data class defaults survive deserialisation. Integration costs a JitPack dependency, a Kotlin requirement and an R8 flag turned off.
- Who is it for?
- GsonFactory fits an Android team whose backend sends inconsistent JSON and whose crash reports are full of JsonSyntaxException traces, and who can accept three setup conditions: a Kotlin environment in the module, Gson 2.13.0 or newer, and android.enableR8.fullMode=false in gradle.properties.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 104 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem is a field with an unexpected type, not broken JSON
GsonFactory is a Gson fault tolerance framework, and its own description is blunt about the goal: no more JSON parsing errors. The scenario it targets is narrow and common. A server returns a JsonObject when there is data and an empty array when there is not, and stock Gson throws. A client field is declared as boolean and the server sends 0 or 1, and stock Gson throws. A client field is declared as int or long and the server sends a float or a double, and stock Gson throws.
None of those are malformed documents. They are well formed JSON whose shape does not match the Java or Kotlin declaration on the client. The framework's answer is to keep parsing and to decide, field by field, what to do with the mismatch.
The design assumption is that the alternative is worse. An Android app that crashes on a production response because one optional field changed shape has an availability problem, and the cost of tolerating the mismatch is that a field can end up with a value nobody asked for.
The audience is therefore mobile teams dealing with servers they do not fully control, and the library is an Android one, published through JitPack and distributed with an app module, a library module and a common.gradle file in the tree.
The table in the README puts it next to stock Gson, moshi and FastJson, and it is worth reading with the scepticism you would apply to any self comparison.
The conversion rules are skip, boolean from number, truncate float to int
The fault tolerance rules are stated as three cases, and they are the whole behaviour of the library in miniature.
If the type the server returned does not match the type the client declared, the framework skips parsing that field and lets the other fields parse normally. If the client declares a boolean and the server returns an integer, a non zero number becomes true and zero becomes false. If the client declares an int or a long and the server returns a floating point number, the value is truncated and assigned.
The supported types are listed in full: bean classes, array collections, Map collections, JSONArray, JSONObject, String, boolean and Boolean, int and Integer, long and Long, float and Float, double and Double, and BigDecimal. The fault tolerance table then maps each of those against the others, showing that a bean can absorb a collection, a string, a boolean or a number, and that a number can absorb a bean, a collection, a string or a boolean.
Skipping a field is the rule that deserves the most thought. It means the target object is constructed with whatever default the field has, and a value that the server did send is discarded. Nothing in the API reports that a field was skipped, unless the caller registers an exception callback.
A parse exception callback is the only hook for knowing a field was lost
The public API is a small static facade over a configured Gson instance, and the first entry point is the one most projects will use.
Gson gson = GsonFactory.getSingletonGson();The rest of the surface lets you replace or extend the configuration. You can set your own Gson instance with setSingletonGson, obtain an already tolerant GsonBuilder with newGsonBuilder, register a type adapter factory, register an instance creator for a type, add a reflection access filter, and set the strategy that converts JSON objects into numbers with setObjectToNumberStrategy.
The one that matters for diagnostics is setOnParseExceptionCallback, which takes an OnParseExceptionCallback. That is where a field that was skipped or coerced can be surfaced, and the documentation's instruction to use the Gson object returned by the framework rather than your own is the point of the whole design: the tolerance lives in the instance, so swapping in a plain Gson silently removes it.
The number strategy hook is there for a specific reason. Gson's default behaviour for an untyped JSON object is to produce Double values, which loses precision on large integers. Being able to set the strategy is how you get an Integer or a Long back, which is the sort of detail that decides whether a large numeric identifier survives a round trip.
Kotlin data class defaults need kotlin-reflect and the primary constructor
The Kotlin handling is the part that goes beyond the JSON mechanics, and it is the reason the library pulls in kotlin-reflect.
The first case is a data class with a default value:
data class DataClassBean(val name: String = "Hello")The README states that with plain Gson the resulting object has name = null rather than the default. The explanation given is about how Gson builds objects: it reflectively creates the instance using the no-argument constructor, then assigns fields from the JSON by name. A default value declared in the primary constructor is never consulted, because that constructor is not the one being called, and a field the server omitted is simply not assigned.
The framework's answer is to bring in the Kotlin reflection library, find the primary constructor that the compiler generated for the data class, and construct the object through it, which preserves the declared defaults.
The second case is a data class with a non-null field and no default:
data class DataClassBean(var name: String)Here the framework skips assigning a value when the server did not return the field or returned it as null, because assigning null to a field declared non-null produces a NullPointerException on first use. The same reasoning applies to List and Map fields: when the server returns null or a wrong type, the framework returns an empty collection rather than null.
The cost of this is a Kotlin environment in the module, an extra reflection dependency, and a note in the README that the Kotlin version in the dependency line should match the project's own version.
Integration is a JitPack repository line, one dependency and an R8 flag
The setup is three parts, and the first one depends on your Gradle version. For Gradle below 7.0 the repository goes into the allprojects repositories block in build.gradle; for 7.0 and above it goes into the dependencyResolutionManagement block in settings.gradle.
dependencyResolutionManagement {
repositories {
maven { url 'https://jitpack.io' }
}
}Then the dependency itself goes into the app module's build.gradle, alongside Gson and the Kotlin reflection library, with a compileOptions block that sets source and target compatibility to Java 1.8.
dependencies {
implementation 'com.github.getActivity:GsonFactory:10.8'
implementation 'com.google.code.gson:gson:2.14.0'
implementation 'org.jetbrains.kotlin:kotlin-reflect:1.5.10'
}Third, gradle.properties needs a flag switched off:
android.enableR8.fullMode=falseThat line is there for a reason, and the README links the issue that tracks it. The library relies on reflective behaviour that the full mode of R8 changes, and the project asks you to disable it rather than shipping keep rules for the whole framework.
Two more conditions are stated as requirements. The module must have a Kotlin environment or the build fails, and Gson must be 2.13.0 or newer or there is a compatibility problem. If upgrading Gson produces an errorprone related compilation failure, the README suggests excluding the error_prone_annotations module from the Gson dependency.
ProGuard rules are needed for Kotlin data classes, and the comparison table is optimistic
There is a second configuration step that is easy to miss and produces a confusing failure. The README warns against obfuscating Kotlin data class bean types, because the reflection that reconstructs the object needs to find the primary constructor, and an obfuscated class name leads to a ClassNotFoundException. The issue on the project tracker is referenced for the details, and the keep rule is a name rule with a public constructor:
The rule is a name keep rule scoped to your bean package, keeping public constructors, so the package path in it has to be replaced with the package where your beans live. That means the rule has to be maintained per project, and it is the one build file change that is easy to forget when a new module of beans appears.
The comparison table lists GsonFactory against Gson, moshi and FastJson with rows for framework size, maintenance status, and eight behavioural questions. Its claims are that only GsonFactory and FastJson can parse a wrongly typed value without error, and that only GsonFactory continues parsing the remaining fields, performs intelligent conversion, adapts Kotlin data class fields that are non-null with no default, and skips null values in the JSON to avoid null pointers. The size row puts the library at 65 KB plus the 283 KB of Gson itself, against 162 KB for moshi and 188 KB for FastJson.
Those are the maintainer's own claims about their own library, in a table where the competitors' issue counts appear as badges. The behavioural rows are testable and the README points to demo unit tests for exactly that, which is the honest way to check the central claim: run the tests and see whether the tolerance behaves as described on the shapes you actually receive.
Apache 2.0, version 10.8, and a last push in July 2026
The licence is Apache 2.0, with the terms in the LICENSE file, which is a permissive choice for a library that sits in the dependency list of a commercial Android app and that vendors a modified Gson behaviour.
The recent tags show the release cadence: 10.8 published on 2026-07-11, 10.5 on 2025-12-14, and 10.3 on 2025-07-28. The dependency coordinate in the README is com.github.getActivity:GsonFactory:10.8, so the version you depend on is the one the README pins.
The last push to the repository was on 2026-07-11, and the project is not archived. The comparison table also states a maintenance status for each library it lists, marking this one, Gson and moshi as under maintenance and FastJson as no longer maintained.
The upgrade cost for a team that already uses this is low in code and non trivial in build. A version bump is a new JitPack coordinate, and the constraint that Gson must be 2.13.0 or newer means the library pins your Gson version floor. The requirement that the module have a Kotlin environment is the one that decides whether the library is usable in your project at all, since a Java only module cannot compile it.
Editorial conclusion
GsonFactory fits an Android team whose backend sends inconsistent JSON and whose crash reports are full of JsonSyntaxException traces, and who can accept three setup conditions: a Kotlin environment in the module, Gson 2.13.0 or newer, and android.enableR8.fullMode=false in gradle.properties. It does not fit a project that would rather fix the contract at the source, since a skipped field is a silent data loss that no type system will flag, and it does not fit a non Android project because the integration path is JitPack and Gradle. Before adopting it, run the demo unit tests the README points at to see the actual tolerance behaviour on your own shapes, and add the keepnames rule for your Kotlin data class packages, because obfuscating them causes the ClassNotFoundException described in issues/43.
Frequently asked questions
How do I add GsonFactory to an Android project?
Add the JitPack repository to the dependencyResolutionManagement block of settings.gradle for Gradle 7.0 and above, or to allprojects in build.gradle below 7.0, then add implementation 'com.github.getActivity:GsonFactory:10.8' to the app module and set android.enableR8.fullMode=false in gradle.properties.
What happens when GsonFactory meets a JSON field of the wrong type?
The framework skips that field and keeps parsing the others. A boolean field fed an integer becomes true for any non zero value, and an int or long field fed a floating point number has the value truncated.
Does GsonFactory need Kotlin in my project?
Yes. The README states that the project must have a Kotlin environment or the build will not compile, and the integration adds the kotlin-reflect dependency, whose version should match the Kotlin version of your project.
Why does my Kotlin data class field come out null with plain Gson?
Gson creates the object with the no-argument constructor and assigns fields from the JSON by name, so a default value declared in the primary constructor is never applied and a field the server omitted stays null. GsonFactory instead uses the Kotlin reflection library to construct the object through the primary constructor, which preserves the defaults.
What licence is GsonFactory released under?
Apache 2.0. The current release is 10.8, published on 2026-07-11, and the library requires Gson 2.13.0 or newer.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/getactivity-gsonfactory)Was this useful?