我使用了一个非常奇怪的api,它的数据字段类型是动态的。
如果发生错误,数据字段将是如下字符串:
{
"code": 2001,
"data": "Error!"
}
而如果成功,则数据字段将是一个对象:
{
"code": 2000,
"data": {
"id": 1,
"name": "example"
}
}
我使用下面的Kotlin代码来反序列化它:
return Gson().fromJson(data, SimpleModel::class.java)
模型定义如下:
import com.google.gson.annotations.SerializedName
class SimpleModel {
@SerializedName("code")
val code = 0
@SerializedName("data")
val data: SimpleData = SimpleData()
}
class SimpleData {
@SerializedName("id")
val id = ""
@SerializedName("name")
val name = ""
}
当没有错误发生时,上面的代码工作正常。但是当错误发生时,抛出异常:
java.lang.IllegalStateException: Excepted BEGIN_OBJECT but was STRING at line 1 column x $path.data
是否有一种方法可以将data
字段反序列化为一个对象或任何对象,并通过代码手动确定其类型?
2条答案
按热度按时间xmakbtuz1#
您需要编写一个自定义的反序列化器,它根据节点的运行时类型决定将
data
反序列化为什么类型,并将该反序列化器注册到您的Gson
示例中。不幸的是,我不熟悉Kotlin语法,所以我只能给予您伪代码。SimpleModel
中的字段data
应该是Object
,或者使类成为泛型-SimpleModel<T>
,并且该字段的类型也应该是T
。1.将输入解析为gson的节点类型-
JsonElement
。1.获取数据字段
1.使用
getAs...()
方法检查类型。1.以字符串形式获取。如果成功,则为字符串,并在
SimpleModel
中设置字符串值。1.如果以字符串的形式获取时出现异常,则以对象-
getAsJsonObject()
的形式获取它,将该对象解析为SimpleData
,并在SimpleModel
中设置此新对象。你可以用我的答案作为灵感,虽然它是关于对象Map器的,但它做的是同样的事情--根据节点类型来决定对象类型,并遵循与上面描述的大致相同的算法。
此外,this guide有关于如何编写自己的反序列化器和注册它的信息。
wfsdck302#
和前面的答案一样,我对Kotlin并不熟悉,下面的解决方案是用Java编写的,但据我所知,使用IntelliJ内置工具将Java转换为Kotlin是很容易的。
success/error对象对是一个典型的问题,您可以创建自己的方法来解决它,但是让我们考虑以下类分别表示success和error对象(Java 17,启用交换机上的模式匹配):
上面的代码可以自我解释。现在的核心部分,需要更多的工作比我以前认为,通过提供你我的第一个评论,似乎不完整。
第一个
下面是它输出到stdout的内容:
简单模型类型适配器工厂测试.简单数据(标识=1,名称=示例)
出错了!
嗯,是的,这是一个“有点”比我的第一个评论所建议的更棘手。