gpt4 book ai didi

json - 使用密封类或 Moshi 接口(interface)时无法为类创建转换器

转载 作者:行者123 更新时间:2023-12-02 13:20:37 24 4
gpt4 key购买 nike

我正在尝试解析来自服务器的 json 数据。它具有动态键,因此我试图让父类具有每个特定节点的共享键和子类。我使用改造和 Moshi 编写了一个 kotlin 代码,但它不起作用。我尝试使用密封类和接口(interface)但没有成功。实际上我更喜欢密封类,但我不知道我做错了什么

interface MyApi {

@GET("/...")
fun fetchMyFeed(): Call<MyResponse>

}

data class MyResponse(
val data: List<ParentResponse>
)
interface ParentResponse{
val name: String
}

data class Child1Response(
val age: String,
val kids: List<KidsResponse>,
val cars: List<CarsResponse>
)

data class Child2Response(
val job: String,
val address: List<AddressResponse>
)


fun fetchAllFeed(): List<Any>? =
try {
val response = api.fetchMyFeed().execute()
if (response.isSuccessful) {
Log.d("check",${response.body()?.data?})
null
} else null
} catch (e: IOException) {
null
} catch (e: RuntimeException) {
null
}```

and the json file is :

{
"data": [
{
"name": "string",
"job": "string",
"address": [
{
"avenue": "string",
"imageUrl": "string",
"description": "string"
}
]
},
{
"name": "string",
"age": "string",
"kids": {
"count": "string",
"working": "string"
},
"cars": [
{
"brand": "string",
"age": "string",
"imageUrl": "string"
}
]
}
]
}

Unable to create converter for class

最佳答案

如果您可以通过预见 json 中的某些值来区分它们,则可以使用 moshi 的 JsonAdapter 来解析不同的 JSON 模型。

例如,考虑具有两个模式的 json 响应,

{
"root": {
"subroot": {
"prop" : "hello",
"type" : "String"
}
}
}

(or)

{
"root": {
"subroot": {
"prop" : 100,
"type" : "Integer"
}
}
}

这里,subroot 有不同的模式(一个包含字符串属性,另一个包含整数属性),可以通过“类型”来识别

您可以创建一个具有公共(public)键的父密封类,并派生几个具有不同键的子类。编写适配器以选择在 json 序列化时要使用的类的类型,并将该适配器添加到 moshi 构建器。

模型类:

class Response {
@Json(name = "root")
val root: Root? = null
}

class Root {
@Json(name = "subroot")
val subroot: HybridModel? = null
}

sealed class HybridModel {
@Json(name = "type")
val type: String? = null

class StringModel : HybridModel() {
@Json(name = "prop")
val prop: String? = null
}

class IntegerModel : HybridModel() {
@Json(name = "prop")
val prop: Int? = null
}
}

JsonReader 的几个扩展方法,

inline fun JsonReader.readObject(process: () -> Unit) {
beginObject()
while (hasNext()) {
process()
}
endObject()
}

fun JsonReader.skipNameAndValue() {
skipName()
skipValue()
}

为“子根” key 选择类类型的混合适配器

class HybridAdapter : JsonAdapter<HybridModel>() {
@FromJson
override fun fromJson(reader: JsonReader): HybridModel {
var type: String = ""

// copy reader and foresee type
val copy = reader.peekJson()
copy.readObject {
when (copy.selectName(JsonReader.Options.of("type"))) {
0 -> {
type = copy.nextString()
}
else -> copy.skipNameAndValue()
}
}

//handle exception if type cannot be identified
if (type.isEmpty()) throw JsonDataException("missing type")

// build model based on type
val moshi = Moshi.Builder().build()
return if (type == "String")
moshi.adapter(HybridModel.StringModel::class.java).fromJson(reader)!!
else
moshi.adapter(HybridModel.IntegerModel::class.java).fromJson(reader)!!
}

@ToJson
override fun toJson(p0: JsonWriter, p1: HybridModel?) {
// serialization logic
}
}

最后使用 HybridAdapter 构建 Moshi 以序列化 HybridModel,

fun printProp(response: Response?) {
val subroot = response?.root?.subroot
when (subroot) {
is HybridModel.StringModel -> println("string model: ${subroot.prop}")
is HybridModel.IntegerModel -> println("Integer model: ${subroot.prop}")
}
}

fun main() {
val jsonWithStringSubroot =
"""
{
"root": {
"subroot": {
"prop" : "hello",
"type" : "String"
}
}
}
"""
val jsonWithIntegerSubroot =
"""
{
"root": {
"subroot": {
"prop" : 1,
"type" : "Integer"
}
}
}
"""

val moshi = Moshi.Builder().add(HybridAdapter()).build()

val response1 = moshi.adapter(Response::class.java).fromJson(jsonWithStringSubroot)
printProp(response1) // contains HybridModel.StringModel

val response2 = moshi.adapter(Response::class.java).fromJson(jsonWithIntegerSubroot)
printProp(response2) // contains HybridModel.IntegerModel
}

关于json - 使用密封类或 Moshi 接口(interface)时无法为类创建转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56887126/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com