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.
来源:https://stackoverflow.com/questions/30001674/gson-deserialize-null-pointer-in-released-apk