Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson deserialize null pointer in released apk

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') } 
like image 718
padeoe Avatar asked May 02 '15 11:05

padeoe


2 Answers

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.

like image 172
Egor Neliuba Avatar answered Oct 05 '22 03:10

Egor Neliuba


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.

like image 28
Ali Nem Avatar answered Oct 05 '22 03:10

Ali Nem