Gson.toJson(PrinterInfo) 返回空对象

Gson.toJson(PrinterInfo) returns empty object

提问人:Gábor 提问时间:11/3/2023 更新时间:11/5/2023 访问量:71

问:

我正在尝试使用 Gson(版本 2.9.0)将对象序列化为 JSON:android.print.PrinterInfo

val type: Class<*> = data.javaClass
json.beginObject()
json.name(type.name)
json.value(gson.toJson(data, type))
Log.d(TAG, data.toString())
json.endObject()

但结果是一个空对象。日志行清楚地表明对象已填充,没有 null 值或类似值(但用于包含 null、漂亮的打印或其他任何内容没有任何区别)。没有例外,只是没有预期的结果。{android.print.PrinterInfo: {}}GsonBuilder()

Android GSON 可包裹

评论

0赞 Gábor 11/3/2023
出于某种原因,Android Studio 没有通知更新版本。现在我尝试使用最新的 2.10.1,没有区别。
0赞 Anna Andreeva Rogotulka 11/4/2023
data.toString() 的输出是什么?
0赞 Gábor 11/4/2023
PrinterInfo 有一个很好的 toString(),它以 “PrinterInfo{id=...,name=...,status=...}” 的格式发出一个长字符串实际上,我可以通过为所涉及的每个类型提供自定义 JsonSerializer 来解决这个问题(考虑到这些是嵌套结构,当然这意味着相当多的自定义序列化程序)。但这是否意味着 Gson 实际上无法序列化任何东西,只能使用基本类型最简单的对象?
0赞 Marcono1234 11/5/2023
您能否包含用于创建 JSON 和日志记录调用的完整代码?我假设是一个 ,但您的代码不包括它,也没有显示您记录 JSON 数据的位置。在您的问题中不是 JSON(成员名称周围缺少它);因此,创建JSON数据的方式可能也存在问题?jsonJsonWriter{android.print.PrinterInfo: {}}"
0赞 Gábor 11/6/2023
我将在答案下方评论该案例的优点,但为了完整起见,您会看到除单个调用之外的完整代码。其余部分编译并作为一个完整的独立单元工作。val json = Gson()

答:

0赞 Marcono1234 11/5/2023 #1

主要问题似乎是您正在尝试从 Android 库序列化一个类,而不为此使用自定义 Gson 适配器。在这种情况下,Gson 将使用反射来访问类的字段,包括表示实现细节的私有字段。

即使这可行并且您得到了一个非空的 JSON 对象,它也会包含类的内部数据,因此它可能因 Android 版本而异(甚至可能在不同的 Android 设备之间?并且不能保证您可以使用这种方式正确地重新创建对象。您可能收到的处于不一致状态且无法正常工作。PrinterInfoGson.fromJsonPrinterInfo

更好的解决方案是为执行序列化(和反序列化)的类(和引用的类)编写自定义 Gson TypeAdapter
或者,因为实现另一个选项可能是使用其方法,而不是将其序列化为 JSON。
PrinterInfoPrinterInfoParcelablewriteToParcel

将来还可以使用 Gson 的 ReflectionAccessFilter 来避免意外依赖基于反射的 Android 库类序列化。


可以说,这并不能回答为什么您问题中的 JSON 对象为空,但它强调了尝试(隐式)使用反射对第三方类进行 JSON 序列化有其缺点,并且还有其他替代方法。

评论

0赞 Gábor 11/6/2023
是的,这就是我最终所做的,它需要不少于十个单独的类型适配器。考虑到它们都是相对简单的数据类型,这正是我最初所期望的,Gson 为我做了这件事。主要是因为它的文档清楚地提到私有字段不仅不是问题,而且明确推荐:github.com/google/gson/blob/main/......从那份文档中,我有一种印象——我认为可能是错误的——它能够自己完成这一切......
0赞 Gábor 11/6/2023
...如果我想做一些与股票转换不同的事情,我只需要提供我自己的适配器。实际上,其余的并不那么重要。我并不特别关心与更高版本的 Android 版本的兼容性,因为我不存储数据。我需要转换才能在当前同一应用程序的两个不同部分之间发送它。而且两者有不同的引擎(Android/Kotlin 和 Flutter/Dart),所以使用包裹也是没有问题的。
0赞 Marcono1234 11/6/2023
Gson 实际上应该能够序列化字段(它将匿名类和本地类序列化为 ,但这不应该在这里适用)。所以应该给出想要的结果;我不确定为什么它没有。但我仍然不建议在(或您无法控制的任何第三方类)上使用它。Gson 用户指南可能会在您自己的类的上下文中提到字段,您可以控制其结构。PrinterInfonullLog.d(TAG, Gson().toJson(data))PrinterInfoprivate
0赞 Marcono1234 11/6/2023
即使只是在运行时暂时使用 Gson 的基于反射的序列化,也可能导致问题,我猜当你使用 .如果有任何字段的值在创建后需要重新计算,并且任何类没有无参数构造函数(请参阅 GsonBuilder.disableJdkUnsafe()),则在反序列化后可能会得到损坏的实例。Gson.fromJson
1赞 Gábor 11/6/2023
很可能是。但我根本不打算使用 fromJson(),我只需要一个方向的转换。实际上,在两个方向上,我都必须发送数据,但另一方将从头开始创建自己的对象。它将从 JSON 中选取和使用数据,但它将使用标准对象创建而不是反序列化。