Gson在发布的apk中反序列化空指针
Gson deserialize null pointer in released apk
我正在编写一个 Android 应用程序,需要使用 gson 反序列化 json 字符串:
{
"reply_code": 001,
"userinfo": {
"username": "002",
"userip": 003
}
}
所以我创建了两个 类:
public class ReturnData {
public String reply_code;
public userinfo userinfo;
}
public class userinfo {
public String username;
public String userip;
}
最后,我的 Java 代码在 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();
}
让我感到困惑的是,当我调试应用程序时,它 运行 很好并输出 "notNULL"。我可以看到对象的每个属性都已正确反序列化。
但是,当我从 Android Studio 生成发布的 apk 和 phone 上的 运行 apk 时,它输出 "isNULL",json 解析失败!
谁能告诉我发生了什么事?!
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')
}
您在 release
构建类型中启用了 ProGuard - minifyEnabled true
。它通过更改 class/variable 名称来混淆代码。
您应该注释您的 class 属性,以便 Gson 知道要查找的内容:
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;
}
这样 Gson 就不会查看属性的名称,但会查看 @SerializedName
注释。
您可以使用@Egor N 提到的 @SerializedName
或者您可以使用
将 Gson class 添加到 proguard-rules.pro
-keep class com.packageName.yourGsonClassName
后者较前者有以下优点:
在编写代码时,您可以将所有 Gson class 放在一个文件夹中,并使用以下方法防止所有 Gson 混淆,这样可以节省大量编码:
-keep class com.packageName.gsonFolder.** { *; }
在Gson classes中的每个字段中添加@SerializedName
不仅耗时,尤其是在Gson文件很多的大型项目中,而且增加了输入错误的可能性代码,如果 @SerializedName
中的参数与字段名称不同。
如果在 Gson class 中使用任何其他方法,例如 getter 或 setter 方法,它们也可能会被混淆。由于名称冲突,不对这些方法使用 @SerializedName
会导致运行时崩溃。
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 ----------
我正在编写一个 Android 应用程序,需要使用 gson 反序列化 json 字符串:
{
"reply_code": 001,
"userinfo": {
"username": "002",
"userip": 003
}
}
所以我创建了两个 类:
public class ReturnData {
public String reply_code;
public userinfo userinfo;
}
public class userinfo {
public String username;
public String userip;
}
最后,我的 Java 代码在 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();
}
让我感到困惑的是,当我调试应用程序时,它 运行 很好并输出 "notNULL"。我可以看到对象的每个属性都已正确反序列化。 但是,当我从 Android Studio 生成发布的 apk 和 phone 上的 运行 apk 时,它输出 "isNULL",json 解析失败!
谁能告诉我发生了什么事?!
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')
}
您在 release
构建类型中启用了 ProGuard - minifyEnabled true
。它通过更改 class/variable 名称来混淆代码。
您应该注释您的 class 属性,以便 Gson 知道要查找的内容:
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;
}
这样 Gson 就不会查看属性的名称,但会查看 @SerializedName
注释。
您可以使用@Egor N 提到的 @SerializedName
或者您可以使用
proguard-rules.pro
-keep class com.packageName.yourGsonClassName
后者较前者有以下优点:
在编写代码时,您可以将所有 Gson class 放在一个文件夹中,并使用以下方法防止所有 Gson 混淆,这样可以节省大量编码:
-keep class com.packageName.gsonFolder.** { *; }
在Gson classes中的每个字段中添加
@SerializedName
不仅耗时,尤其是在Gson文件很多的大型项目中,而且增加了输入错误的可能性代码,如果@SerializedName
中的参数与字段名称不同。如果在 Gson class 中使用任何其他方法,例如 getter 或 setter 方法,它们也可能会被混淆。由于名称冲突,不对这些方法使用
@SerializedName
会导致运行时崩溃。
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 ----------