首页 > 解决方案 > 如果 Gson 序列化失败,如何跳过字段?

问题描述

例如,服务器响应#1 有name对象:

     {
       "id":"vfa45f42", 
       "name": { 
                "firstName":"UserFirstName",
                "lastName":"UserLastName"
         }
    }

但有时服务器响应#2 有name其他用户对象的字符串(那是因为服务器有 MongoDB,在 v1 是String,但在 v2 是Object):

    {
        "id":"abfaf453", 
        "name":"OneSentenceUserName"
    }

所以,如果我用 response#2 这个:

val type = object : TypeToken<User>() {}.type
gson.fromJson(responseString, type)

在哪里

data class User(val id:String, val name: Name)

data class Name(val firstName: String, val lastName: String)

错误是:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line ...

我希望name = nullString在 json

标签: javaandroidkotlingson

解决方案


保留您的实际类UserName,您可以创建一个自定义TypeAdapter并通过自己阅读创建一个完整Name的单个name字符串或完整的 JSON 对象。

class NameAdapter : TypeAdapter<Name>() {

    @Throws(IOException::class)
    override fun read(reader: JsonReader): Name? {
        return when(reader.peek()) {
            // if { "name": null }
            JsonToken.NULL -> {
                reader.nextNull()
                null
            }
            // if { "name": "SomeString" }
            JsonToken.STRING -> {
                Name(reader.nextString(), "")
            }
            //if { "name": { "firstName": "some", "lastName": "thing" }
            JsonToken.BEGIN_OBJECT -> {
                var firstName = ""
                var lastName = ""

                reader.beginObject()
                while (reader.hasNext()) {
                    val peek = reader.peek()
                    if(peek == JsonToken.END_OBJECT) break
                    else if(peek == JsonToken.NAME) {
                        when(reader.nextName()) {
                            // it will produce an exception if it isn't a string
                            "firstName" -> firstName = reader.nextString()
                            "lastName" -> lastName = reader.nextString()
                        }
                    }
                }
                reader.endObject()
                Name(firstName, lastName)
            }
            else -> throw IOException("Unable to parse a name")
        }
    }

    @Throws(IOException::class)
    override fun write(writer: JsonWriter, value: Name?) {
        if(value == null) {
            writer.nullValue()
            return
        }
        writer.beginObject()
        writer.name("firstName")
        writer.value(value.firstName)
        writer.name("lastName")
        writer.value(value.lastName)
        writer.endObject()
    }
}

然后您可以将此类型的适配器添加到您的 gson 构建器中。

val gson = GsonBuilder().registerTypeAdapter(Name::class.java, NameAdapter()).build()

它将在每种情况下正确反序列化名称并生成一个完整的Name类。


推荐阅读