Skip to content

Commit 00ae397

Browse files
authored
Adjust Troubleshooting Guide ProGuard / R8 section (#2844)
1 parent 0eec6f3 commit 00ae397

File tree

2 files changed

+23
-14
lines changed

2 files changed

+23
-14
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Please use the ['gson' tag on StackOverflow](https://stackoverflow.com/questions
7979

8080
### ProGuard / R8
8181

82-
See the details in the related section in the [Troubleshooting guide](Troubleshooting.md#proguard--r8).
82+
See the details in the related section in the [Troubleshooting guide](Troubleshooting.md#proguard-r8).
8383

8484
### Related Content Created by Third Parties
8585
* [Gson Tutorial](https://www.studytrails.com/java/json/java-google-json-introduction/) by `StudyTrails`

Troubleshooting.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ This guide describes how to troubleshoot common issues when using Gson.
2323
- When using `TypeToken` make sure you don't capture a type variable. For example avoid something like `new TypeToken<List<T>>()` (where `T` is a type variable). Due to Java [type erasure](https://dev.java/learn/generics/type-erasure/) the actual type of `T` is not available at runtime. Refactor your code to pass around `TypeToken` instances or use [`TypeToken.getParameterized(...)`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/reflect/TypeToken.html#getParameterized(java.lang.reflect.Type,java.lang.reflect.Type...)), for example `TypeToken.getParameterized(List.class, elementType)` where `elementType` is a type you have to provide separately.
2424

2525
If you are using a code shrinking tool such as ProGuard / R8 (for example when building an Android app), make sure it is correctly configured to keep generic signatures and to keep Gson's `TypeToken` class.
26-
See the [ProGuard / R8](#proguard--r8) section for more information.
26+
See the [ProGuard / R8](#proguard-r8) section for more information.
2727

2828
## <a id="reflection-inaccessible"></a> `InaccessibleObjectException`: 'module ... does not "opens ..." to unnamed module'
2929

@@ -78,7 +78,7 @@ See the section below, it's related to this issue.
7878
**Reason:** You probably have not configured ProGuard / R8 correctly; probably the field names are being obfuscated and their naming changed between the versions of your app
7979

8080
**Solution:** Make sure you have configured ProGuard / R8 correctly to preserve the names of your fields.
81-
See the [ProGuard / R8](#proguard--r8) section for more information.
81+
See the [ProGuard / R8](#proguard-r8) section for more information.
8282

8383
If you want to preserve backward compatibility for you app you can use [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html) on the fields to specify the obfuscated name as alternate, for example: `@SerializedName(value = "myprop", alternate = "a")`
8484

@@ -227,7 +227,8 @@ Alternatively you can call [`nullSafe()`](https://www.javadoc.io/doc/com.google.
227227

228228
**Symptom:** Properties are missing in the JSON output
229229

230-
**Reason:** Gson by default omits JSON null from the output (or: ProGuard / R8 is not configured correctly and removed unused fields)
230+
**Reason:** Gson by default omits JSON null from the output\
231+
(or: ProGuard / R8 is not configured correctly and removed unused fields, see the [ProGuard / R8](#proguard-r8) section)
231232

232233
**Solution:** Use [`GsonBuilder.serializeNulls()`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html#serializeNulls())
233234

@@ -282,11 +283,11 @@ If that fails with a `NullPointerException` you have to try one of the other way
282283
- The name you have specified with a [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html) annotation for a field collides with the name of another field
283284
- Or, the [`FieldNamingStrategy`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/FieldNamingStrategy.html) you have specified produces conflicting field names
284285
- Or, a field of your class has the same name as the field of a superclass
285-
- Or, you are using an obfuscation tool such as ProGuard or R8 and it has renamed the fields; in that case see [this troubleshooting point](#android-app-random-names)
286+
- Or, you are using an obfuscation tool such as ProGuard or R8, and it has renamed the fields; in that case see the [ProGuard / R8](#proguard-r8) section
286287

287288
Gson prevents multiple fields with the same name because during deserialization it would be ambiguous for which field the JSON data should be deserialized. For serialization it would cause the same field to appear multiple times in JSON. While the JSON specification permits this, it is likely that the application parsing the JSON data will not handle it correctly.
288289

289-
**Solution:** First identify the fields with conflicting names based on the exception message. Then decide if you want to rename one of them using the [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html) annotation, or if you want to [exclude](UserGuide.md#excluding-fields-from-serialization-and-deserialization) one of them. When excluding one of the fields you have to apply the exclusion for both serialization and deserialization (even if your application only performs one of these actions) because the duplicate field check cannot differentiate between these actions.
290+
**Solution:** First identify the fields with conflicting names based on the exception message. Then decide if you want to rename one of them using the [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html) annotation or a [`FieldNamingStrategy`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/FieldNamingStrategy.html), or if you want to [exclude](UserGuide.md#excluding-fields-from-serialization-and-deserialization) one of them. When excluding one of the fields you have to apply the exclusion for both serialization and deserialization (even if your application only performs one of these actions) because the duplicate field check cannot differentiate between these actions.
290291

291292
## <a id="java-lang-class-unsupported"></a> `UnsupportedOperationException` when serializing or deserializing `java.lang.Class`
292293

@@ -349,7 +350,7 @@ For older Gson versions a `RuntimeException` with message 'Missing type paramete
349350
-keep class * extends com.google.gson.reflect.TypeToken
350351
```
351352

352-
See the [ProGuard / R8](#proguard--r8) section for more information.
353+
See the [ProGuard / R8](#proguard-r8) section for more information.
353354

354355
Note: For newer Gson versions these rules might be applied automatically; make sure you are using the latest Gson version and the latest version of the code shrinking tool.
355356

@@ -376,7 +377,7 @@ For Android you can add this rule to the `proguard-rules.pro` file, see also the
376377

377378
For Android you can alternatively use the [`@Keep` annotation](https://developer.android.com/studio/write/annotations#keep) on the class or constructor you want to keep. That might be easier than having to maintain a custom R8 configuration.
378379

379-
Note that the latest Gson versions (> 2.10.1) specify a default R8 configuration. If your class is a top-level class or is `static`, has a no-args constructor and its fields are annotated with Gson's [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html), you might not have to perform any additional R8 configuration.
380+
Note that the latest Gson versions (2.11.0 or newer) specify a default R8 configuration. See the [ProGuard / R8](#proguard-r8) section for more information.
380381

381382
## <a id="typetoken-type-variable"></a> `IllegalArgumentException`: 'TypeToken type argument must not contain a type variable'
382383

@@ -397,10 +398,18 @@ For backward compatibility it is possible to restore Gson's old behavior of allo
397398
- This does not solve any of the type-safety problems mentioned above; in the long term you should prefer one of the other solutions listed above. This system property might be removed in future Gson versions.
398399
- You should only ever set the property to `"true"`, but never to any other value or manually clear it. Otherwise this might counteract any libraries you are using which might have deliberately set the system property because they rely on its behavior.
399400

400-
## ProGuard / R8
401+
## <a id="proguard-r8"></a> ProGuard / R8
401402

402-
If you use Gson as a dependency in an Android project which uses R8 or ProGuard as code shrinking and obfuscation tool you don't have to do anything.
403-
The specific rules are [already bundled](gson/src/main/resources/META-INF/proguard/gson.pro) (from Gson 2.11.0) into
404-
the JAR which can be interpreted by R8 automatically. For users who still use older Gson versions, you may need to
405-
copy the rules from the [`gson.pro`](gson/src/main/resources/META-INF/proguard/gson.pro) file into your own ProGuard
406-
configuration file.
403+
If you use Gson as a dependency in an Android project which uses ProGuard or R8 as code shrinking and obfuscation tool you don't need custom ProGuard rules in most cases.
404+
The Gson-specific rules are [already bundled](gson/src/main/resources/META-INF/proguard/gson.pro) (from Gson 2.11.0) into the Gson JAR which can be interpreted by R8 automatically.
405+
406+
However, your classes must adhere to the following:
407+
- must have a no-args constructor\
408+
(and be a top-level or `static` class to avoid implicit constructor arguments)
409+
- fields must be annotated with [`@SerializedName`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html)
410+
411+
Alternatively you can configure ProGuard or R8 to keep your classes as they are, for example by [specifying custom ProGuard rules or by using `@Keep` on the classes](https://developer.android.com/build/shrink-code#keep-code).
412+
However, this might completely disable some optimizations and obfuscation for these classes.
413+
414+
If you still use a Gson version older than 2.11.0 or if you are using ProGuard for a non-Android project ([related ProGuard issue](https://github.com/Guardsquare/proguard/issues/337)),
415+
you may need to copy the rules from the [`gson.pro`](gson/src/main/resources/META-INF/proguard/gson.pro) file into your own ProGuard configuration file.

0 commit comments

Comments
 (0)