28

I'm writing an Android app need using gson to deserialize the json string:

{
    "reply_code": 001,
    "userinfo": {
        "username": "002",
        "userip": 003
    }
}

so I create two classes:

public class ReturnData {
    public String reply_code;
    public userinfo userinfo;
}

public class userinfo {
    public String username;
    public String userip;
}

finally, my Java code in MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Context context= MainActivity.this;

    //Test JSON
    String JSON="{\"reply_code\": 001,\"userinfo\": {\"username\": \"002\",\"userip\": 003}}";
    Gson gson = new Gson();
    ReturnData returnData=gson.fromJson(JSON,ReturnData.class);

    if(returnData.reply_code==null)
        Toast.makeText(context,"isNULL",Toast.LENGTH_SHORT).show();
    else
        Toast.makeText(context,"notNULL",Toast.LENGTH_SHORT).show();
}

What made me confused is, when I debug the app,it ran well and output "notNULL".I can see the every attribution of the object has been deserialized properly. However,when I generated released apk from Android Studio and run apk on phone,it output "isNULL",the json resolution failed!

Who can tell me what happened?!

PS:build.gradle:

apply plugin: 'com.android.application'
android {
compileSdkVersion 19
buildToolsVersion "19.1"

defaultConfig {
    applicationId "com.padeoe.autoconnect"
    minSdkVersion 14
    targetSdkVersion 21
    versionCode 1
    versionName "2.1.4"
}
buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile files('src/gson-2.3.1.jar')
}
padeoe
  • 404
  • 4
  • 9

3 Answers3

51

You have ProGuard enabled in your release build type - minifyEnabled true. It obfuscates the code by changing class/variable names.

You should annotate your class properties, so Gson knows what to look for:

public class ReturnData {
    @SerializedName("reply_code")
    public String reply_code;
    @SerializedName("userinfo")
    public userinfo userinfo;
}

public class userinfo {
    @SerializedName("username")
    public String username;
    @SerializedName("userip")
    public String userip;
}

This way Gson won't look at the properties' names, but will look at @SerializedName annotation.

Egor Neliuba
  • 14,784
  • 7
  • 59
  • 77
  • 1
    This answer took WAAAAY to long to find. Well done @Egor N. – PGMacDesign Feb 05 '16 at 16:23
  • Just FYI, the code in your example says `@SerialiazedName`. It's supposed to be `@SerializedName` – w3bshark Jul 29 '16 at 13:46
  • Thanks to you because it saved my whole day – Amandeep Rohila Jun 03 '17 at 10:30
  • Has been searching for a way to fix this bug for 2 days. Great thanks. – Asim Gasimzade Jun 14 '18 at 07:51
  • I have the same issue, and I use @SerializedName in my class yet, in my case when using toJson() it only deserialized the 1st key/value pair and discarded the rest, I – Jamal S Sep 06 '18 at 21:18
  • I did with serializeName but still it return blanck object. Someone plz reply. String cameraResponseJson = new Gson().newBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(mCameraResponse); This is how I converting pojo to JSON – Krunal Shah Nov 28 '19 at 06:51
  • This did not help , only solution is exclude Serialized name from obfuscation. -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } – Nasif Noorudeen Oct 18 '22 at 19:25
30

You can either use @SerializedName as mentioned by @Egor N or you may add the Gson classes to the proguard-rules.pro by using

-keep class com.packageName.yourGsonClassName

The latter has the following advantages over the former:

  • when writing your code you can put all your Gson class in a folder and keep all of them from obfuscation using the following, which saves a lot of coding:

    -keep class com.packageName.gsonFolder.** { *; }
    
  • Adding @SerializedName to each field in Gson classes is not only time-consuming especially in large projects with lots of Gson files but also increases the possibility of mistakes entering the code, if the argument in the @SerializedName is different from the field name.

  • If any other methods, such as getter or setter methods are used in the Gson class, they may also get obfuscated. Not using @SerializedName for these methods causes crash in runtime due to conflict in names.

Ali Nem
  • 5,252
  • 1
  • 42
  • 41
  • 1
    For me, it works after adding additional info **private fields** like this -keep class com.packageName.yourGsonClassName{ private ; } – P Yellappa Dec 07 '17 at 10:47
0

Add This Lines inside pro-guard file

    ##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

##---------------End: proguard configuration for Gson  ----------
adarsh
  • 403
  • 3
  • 8