当前位置: 首页 > 知识库问答 >
问题:

格森。toJson返回null[ProGuard issue]

冀弘济
2023-03-14

用户错误报告显示Gson()。toJson(obj)偶尔会返回{},但对于大多数用户来说,它工作正常。

我访问了一位用户,他在手机上遇到了错误并调试了应用程序,我制作了Toast来显示发送到服务器的内容,我看到Toast显示了{},并且记录和ID不是null

这是我所做的。

private class ClassA{
        String ID;
        ArrayList<ClassB> Records;

        ClassA(String ID, ArrayList<ClassB> Records) {
            this.ID= ID;
            this.Records= Records;
        }
 }

 private class ClassB {
        int T;
        int F;
        String D;

        ClassB (int T, int F, String D) {
            this.T= T;
            this.F = F;
            this.D= D;
        }

}

这里我做序列化对象

ClassA obj = new ClassA(ID,Records); 
String json = new Gson().toJson(obj);

但是new Gson()。toJson(obj)对于一些用户来说是正确的,但是对于一些用户来说返回{}

服务器数据库显示一些用户发送了数据{},但一些用户发送了正确的json。经过一些研究,我发现了新的Gson()。toJson(obj)返回{}。没有Web服务问题,也没有数据库问题。

额外信息

ArrayList<ClassB> Records= new ArrayList<>();
Records.add(new ClassB(Integer.valueOf(t.toString()), Integer.valueOf(f.toString()),d.toString()));
ClassA obj = new ClassA(ID,Records); 
String json = new Gson().toJson(obj);

数据库

id    | data
----------------
c89   | {"ID":"c89","Records":[{"T":0,"F":0,"D":"2019/04/11 05:48 PM"}]} correct one

c90   | {} bug

空输入测试

我做了以下测试,发现问题超出了空输入

ArrayList<ClassB> Records= new ArrayList<>();
ClassA obj = new ClassA(null,Records);    
Toast.makeText(getApplicationContext(),new Gson().toJson(obj ),Toast.LENGTH_LONG).show();

Toast显示{“记录”:[]}。比上一种情况更糟的情况永远不会发生

IDE还说

if(ID!=null && Records!=null) <= this condition is always true 
ClassA obj = new ClassA(ID,Records); 

前进的规则。赞成的意见

##---------------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.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements 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>;
}

##---------------End: proguard configuration for Gson  ----------

如何使其对所有用户都正常工作?

评论

这应该是不可能的,你需要更多关于{}情况的细节,例如,它是否一致,是否由于多线程,是否是一个特定的JDK版本

没有任何多线程现象。例如,noRunnablenoAsycTasknoThread。它只是一个普通的片段,从内容提供者获取数据并创建json字符串。

建议的解决方案具有相同的结果!

ClassA obj = new ClassA(ID,Records); 
Gson gson = new GsonBuilder().serializeNulls().create();
Toast.makeText(getActivity(), gson.toJson(obj), Toast.LENGTH_LONG).show();

Toast再次显示{}

共有3个答案

齐望
2023-03-14
ArrayList<ClassB> Records= new ArrayList<>();
ClassA obj = new ClassA(null,Records);    
Toast.makeText(getApplicationContext(),new Gson().toJson(obj 
),Toast.LENGTH_LONG).show();

在这种情况下,您可以将rRecord arraylist设置为空而不是空。尝试此检查

if(!Records.isEmpty()){ 
 // show toast
}
裴泰平
2023-03-14

我只是胡乱猜测,我看到你在一条评论中提到,ClassAClassB是片段中的内部类。所以,如果你还没有尝试的话,也许你可以尝试一些事情。

第一:把它们变成静态的内部类怎么样?

private static class ClassA {
    ...
}

private static class ClassB {
    ...
}

因为没有其他人使用它而将类声明为内部类是可以的,我有时也这样做。但是非静态内部类有点依赖于它的父对象实例,所以当它只是一个简单的bean/DTO类时,将它们声明为静态内部类要安全得多。

第二:尝试摆弄关于这些类的ProGuard配置

>

  • 这里有一个关于设置ProGuard以保持内部类的stackoverflow问题。

    复习-继续上课

    第三:也许可以尝试将这些类提取到普通类中,以缩小可疑区域。

    如果它仍然不起作用,那么问题可能出在其他地方,可能是客户端移动设备的特定构建/版本或其他东西。

  • 左丘耀
    2023-03-14

    这是因为ClassA中的ID记录为空。Gson默认情况下不会序列化null,实际上有一个方法可以启用序列化null,我几乎总是启用该方法

    private static final Gson GSON = new GsonBuilder().serializeNulls().create();
    

    我建议您保留一个Gson的静态实例,这样您就不必每次想序列化时都创建一个静态实例。

    如果不想序列化null,那么可以使用其他一些选项来修复代码,例如在ClassA的构造函数中进行null检查。

     类似资料:
    • 我正在尝试使用方法,但它正在重新生成类的对象哈希代码,例如: 但是,我可以检索用户。没有任何问题和所有关系的专业知识: 这是我的Gson方法: 这是我的MyTypeAdapter: } 那么,如何让实际返回一个Json字符串,以便我可以使用Gson. FromJson在我的另一端?提前谢谢。

    • 我想从我的对象生成一个JSON字符串: 每次我尝试这样做,我得到这个错误: 这些是我的BomItem类的属性: 我引用的BomModule类的属性: 知道是什么导致了这个错误吗?我该如何修复它?

    • 我有以下输出: 但问题是玩家阵列来得太早,部分初始细节被遗漏了。 这是我的代码: 你可以在这篇文章中找到游戏、玩家头像和游戏玩家类的详细信息:https://stackoverflow.com/a/33048622 有人知道我怎样才能正确订购这个吗?

    • 当我将Object转换为Json时,我遇到了大十进制精度丢失的问题。 假设我有Pojo类, 现在我将值设置为Pojo,然后转换为JSON 第一次测试-正确输出 第二次测试-输出错误(失去BigDecimal精度) 第三次测试-输出错误(失去BigDecimal精度) 令人惊讶的是,每当BigDecimal值的长度更大时,它也会截断小数点。json转换有什么问题。你能给我提供解决方案吗?

    • 我有两个活动和两个布局。当我在第一个活动中显示列表时,一切都正常,并在单击时给出列表中项目的编号,但当我尝试在第二个活动中重复相同的内容时,它会告诉我RecycleServiceClickListener侦听器为空。 适配器: 第一项活动: 第二项活动: 错误: 我不明白为什么在第一种情况下,它正常处理单击,而在第二种情况下,它说RecyclerViewClickListener为null

    • 这是我的代码: 以下是我的ModelClass: 地址.java 我尝试了几个组合,但没有一个能告诉我地址。虽然我的应用程序的前一个版本上的相同代码运行良好。旧版本应用程序中返回的地址为: 地址[addressLines=[0:"俄亥俄,美国"],功能=俄亥俄,admin=俄亥俄,sub-admin=null,locality=null,通途=null,postalCode=null,国家代码=美