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') }
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With