数据类对象或数组

时间:2019-03-05 05:23:18

标签: arrays json kotlin gson

我有一个Kotlin数据类,它的arg可以是Object或Array。有没有一种方法可以将字符串反序列化到此类中,并且不在乎是否不是Array,而是以某种方式将其放入一个由一个组成的数组中?

data class Game(var name:List<NameItem>)
data class NameItem(var title: String, var id: Int)

数据可以以单个对象或对象数组的方式返回(我无法控制数据,因为它是第三方数据。

jsonString = "{"game":{"name":{"title":"GameName","id":22}}}"
jsonString = "{"game":{"name":[{"title":"GameName","id":22},{"title":"GameName2","id":23}]}}"

game: Game? = Gson().fromJson(jsonString  Game::class.java)

2 个答案:

答案 0 :(得分:2)

您必须编写自定义JsonDeserializer。两者或您的班级应具有相同的父班级。然后,为此特定类型编写自定义JsonDeserializer

例如:

sealed class GameParent() {
    data class Game(val name: String): GameParent()
    data class GameList(val games: List<Game>): GameParent()
}

class GameDeserializer : JsonDeserializer<GameParent> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): GameParent {
        with(json) {
           if(isJsonObject) {
             // parse as Game
           }

           if(isJsonArray) {
             // parse as GameList
           }
        }
    }
}

然后,必须在您的GsonBuilder中注册此自定义JsonDeserializergsonBuilder.registerTypeAdapter(GameParent::class.java, GameDeserializer());

现在,只要您的Gson期望GameParent将使用注册的反序列化器。

答案 1 :(得分:1)

我对解决任务的建议

我的解决方案,如果名称是对象,则将其替换为数组

data class Game(var name:List<NameItem> )
data class NameItem(var title: String, var id: Int)



fun main(args: Array<String>) {
    var json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1},{\"title\":\"game 2\",\"id\":2}]}}"
    println(useJsonParser(json))    //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
    json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1}]}}"
    println(useJsonParser(json))    //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
    json = "{\"game\":{\"name\":{\"title\":\"game 1\",\"id\":1}}}" // not array
    println(useJsonParser(json))    //Game(name=[NameItem(title=game 1, id=1)])
}

版本1-创建并注册了适配器link @Cililing

fun useJsonParser(json: String): Game? {
    val gson = GsonBuilder().registerTypeAdapter(Game::class.java, GameDeserializer()).create()
    return gson.fromJson(json, Game::class.java)
}

class GameDeserializer : JsonDeserializer<Game?> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Game? {
        val gameJson = json!!.asJsonObject.get("game")
        if (gameJson.isJsonObject) {
            val jsonName = gameJson.asJsonObject["name"]
            val list = if (jsonName.isJsonObject) {
                arrayOf(Gson().fromJson(jsonName, NameItem::class.java))
            } else {
                val fromJson = Gson().fromJson(jsonName, Array<NameItem>::class.java)
                fromJson
            }.toList()
            return Game(list)
        }
        return null
    }
}

第2版-处理响应

fun useJsonParser(json:String):Game?{
    val jsonObject = JsonParser().parse(json).asJsonObject.get("game")
    if(jsonObject.asJsonObject["name"].isJsonObject){
        val jsonName = jsonObject.asJsonObject["name"].asJsonObject
        val array = JsonArray()
        array.add(jsonName)
        jsonObject.asJsonObject.add("name", array) // rewrite origin JSON
    }

    return Gson().fromJson(jsonObject, Game::class.java)

}

vesrion 3-添加适配器TypeToken>()

fun useJsonParser(json: String): Game? {
    val type = object : TypeToken<MutableList<NameItem>>() {}.type
    val gson = GsonBuilder().registerTypeAdapter(type, NameItemDeserializer()).create()
    return gson.fromJson(JsonParser().parse(json).asJsonObject.get("game"), Game::class.java)
}

class NameItemDeserializer : JsonDeserializer<List<NameItem>?> {
    override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext?): List<NameItem>? {
        with(json){
            return if(isJsonObject){
                arrayListOf(Gson().fromJson(this,NameItem::class.java))
            }else{
                Gson().fromJson(this,Array<NameItem>::class.java).toList()
            }
        }
    }
}