Gson Will Crash at Enum Fields When Enabling Proguard

Recently we used Gson to convert data into JSON string and saved into Preference as cache. Everything looks good except release app crashed when reading JSON cache on release build.

  • Root Cause of Crash when Gson serialized Enum with Proguard

This issue might crash here: the name of Enum constant is different from Enum filed. This is because Proguard would modifies the enums’ constant names and Gson would throw NoSuchFieldException when deserializing enum constants from JSON data.

  • How to resolve this crash

To solve this problem, I have 2 solutions.

  1. Paring enums via @SerializedName annotation:

To add @SerializedName for each Enum type, as following,

public enum CarBrand{
@SerializedName("bmw")
BMW,
@SerializedName("mercedes")
Mercedes,
@SerializedName("lamborghini")
Lamborghini
}

, and Gson would use serialized name for JSON form.

2. Create a type adapter (e.g. LowercaseEnumTypeAdapterFactory) for Gson

Gson office document offers a LowercaseEnumTypeAdapterFactory; to import this adapter into project, and use GsonBuilder().registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory()) to create Gson.
https://gist.github.com/b44272a1a53866f129d0df60b1ab28c6.git

3. Use Keep to make proguard ignore Enum

Thanks for Jo P. and Torbjørn Sørli’s suggestion.

We can also add -keepclassmembers enum * { *; } to our proguard-rules-config file. This also works.

First solution looks easier, however, we have lots enums and I afraid someone will forget to add corresponding serialized names for each enum. So I prefer second solution to implement a factory that creates a type adapter that will write enums in lowercase and map it to the correct constant.

By the way, if we used EnumMap, only @SerializedName won’t work with enum types. We have to use GsonBuilder.enableComplexMapKeySerialization() to avoid this EnumMap problem.

Lead Android & iOS Mobile Engineer at Yahoo (Verizon Media) Taiwan https://www.linkedin.com/in/hanruyeh/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store