您可以通过使用自定义TypeAdapter 来实现这一点,因为它可以让您决定如何处理JsonReader 返回的令牌。
假设您有一个类型 Response 表示您在上面粘贴的 JSON 字符串(类似于 class Result(val people: List<Person>)),我认为这里的关键点是提供一个 TypeAdapter<List<Person>>,因为这样可以过滤掉无效的Person 对象 - 您不能简单地创建一个 TypeAdapter<Person> 来为无效的 Person 对象返回一个 null 值,因为 people 被定义为一个不可为空的对象列表(即 List<Person> 而不是 @ 987654332@.
上述的概念证明是:
data class Person(val name: String, val surname: String, val age: String)
class Result(val people: List<Person>)
fun main() {
val json = """
{
"people":[
{
"name":"Jon",
"surname":"Snow",
"age":"34"
},
{
"name":"Ted",
"surname":"Mosby",
"age":35
},
{
"name":"John",
"surname":"Smith",
"age": "40"
}
]
}""".trimIndent()
val gson = GsonBuilder().registerTypeAdapterFactory(PersonListTypeAdapterFactory).create()
val result = gson.fromJson(json, Result::class.java)
println("Deserialized: ${result.people}")
println("Serialized: ${gson.toJson(result)}")
}
object PersonListTypeAdapterFactory : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType != List::class.java || (type as? ParameterizedType)?.actualTypeArguments?.contains(Person::class.java) == false) {
return null
}
val delegate: TypeAdapter<List<Person>> = gson.getDelegateAdapter(this, type) as TypeAdapter<List<Person>>
return PersonListTypeAdapter(delegate) as TypeAdapter<T>
}
}
class PersonListTypeAdapter(private val delegate: TypeAdapter<List<Person>>) : TypeAdapter<List<Person>>() {
override fun write(out: JsonWriter, value: List<Person>) {
delegate.write(out, value)
}
override fun read(input: JsonReader): List<Person> {
input.beginArray()
val people = mutableListOf<Person>()
while (input.peek() != JsonToken.END_ARRAY) {
val person = readPerson(input)
if (person != null) {
people.add(person)
}
}
input.endArray()
return people
}
private fun readPerson(input: JsonReader): Person? {
input.beginObject()
// initialising everything with nulls is a bit ugly
var name: String? = null
var surname: String? = null
var age: String? = null
var token = input.peek()
while (token != JsonToken.END_OBJECT) {
when (input.nextName()) {
"name" -> name = input.nextString()
"surname" -> surname = input.nextString()
"age" -> {
token = input.peek()
age = if (token == JsonToken.STRING) {
input.nextString()
} else {
input.skipValue()
// logging if needed
null
}
}
}
token = input.peek()
}
input.endObject()
if (listOf(name, surname, age).none(Objects::isNull)) {
return Person(name!!, surname!!, age!!)
}
return null
}
}
该代码将打印:
Deserialized: [Person(name=Jon, surname=Snow, age=34), Person(name=John, surname=Smith, age=40)]
Serialized: {"people":[{"name":"Jon","surname":"Snow","age":"34"},{"name":"John","surname":"Smith","age":"40"}]}
我很确定还有很大的改进空间?