我正在尝试从服务器解析json数据,它具有动态密钥,因此我试图像父类一样为每个特定节点具有共享密钥和子类。我使用翻新和Moshi编写了kotlin代码,但无法正常工作。我尝试使用密封的类和接口没有成功。实际上,我更喜欢在密封类中使用,但我不知道自己在做什么错事
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
答案 0 :(得分:1)
如果可以通过预知JSON中的某些值来区分它们,则可以使用moshi的JsonAdapter来解析不同的JSON模型。
例如,考虑具有两个模式的json响应,
{
"root": {
"subroot": {
"prop" : "hello",
"type" : "String"
}
}
}
(or)
{
"root": {
"subroot": {
"prop" : 100,
"type" : "Integer"
}
}
}
在这里,子根目录具有不同的模式(一个包含字符串属性,另一个包含整数属性),可以通过“类型”来标识
您可以创建具有公共密钥的父级密封类,并派生少量具有不同密钥的子类。编写一个适配器以选择json序列化时要使用的类的类型,然后将该适配器添加到moshi builder中。
模型类:
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()
}
HybridAdapter为“ subroot”键选择类的类型
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
}