Moshi工厂在从json字符串反序列化时忽略空值并使用kotlin默认值
基于Moshi的这一问题,对Moshi为什么以及如何以这种方式处理空值进行了一些很好的讨论。虽然这对我来说很有意义,但不幸的是,我正在使用一个间歇返回空值的api,我得到的最好反馈是我们应该忽略它们。在上面链接的问题中,一个库贡献者提到这个工厂可能会有所帮助Moshi工厂在从json字符串反序列化时忽略空值并使用kotlin默认值,kotlin,moshi,Kotlin,Moshi,基于Moshi的这一问题,对Moshi为什么以及如何以这种方式处理空值进行了一些很好的讨论。虽然这对我来说很有意义,但不幸的是,我正在使用一个间歇返回空值的api,我得到的最好反馈是我们应该忽略它们。在上面链接的问题中,一个库贡献者提到这个工厂可能会有所帮助 @Retention(RUNTIME) @Target(CLASS) annotation class DefaultIfNull class DefaultIfNullFactory : JsonAdapter.Factory {
@Retention(RUNTIME)
@Target(CLASS)
annotation class DefaultIfNull
class DefaultIfNullFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>,
moshi: Moshi): JsonAdapter<*>? {
if (!Types.getRawType(type).isAnnotationPresent(
DefaultIfNull::class.java)) {
return null
}
val delegate = moshi.nextAdapter<Any>(this, type, annotations)
return object : JsonAdapter<Any>() {
override fun fromJson(reader: JsonReader): Any? {
@Suppress("UNCHECKED_CAST")
val blob = reader.readJsonValue() as Map<String, Any?>
val noNulls = blob.filterValues { it != null }
return delegate.fromJsonValue(noNulls)
}
override fun toJson(writer: JsonWriter, value: Any?) {
return delegate.toJson(writer, value)
}
}
}
}
class NullSkipperTest {
@DefaultIfNull
data class ClassWithDefaults(val foo: String, val bar: String? = "defaultBar")
@Test
fun skipNulls() {
//language=JSON
val json = """{"foo": "fooValue", "bar": null}"""
val adapter = Moshi.Builder()
.add(DefaultIfNullFactory())
.add(KotlinJsonAdapterFactory())
.build()
.adapter(ClassWithDefaults::class.java)
val instance = adapter.fromJson(json)!!
check(instance.bar == "defaultBar")
}
}
我所不知道的是,工厂会在类中的每个字段上移动,也会在类中移动,所以当我最初使用工厂时,我认为它是完美的,但它确实会在每个类中的每个字段上被调用,转换失败,然后只返回值
我现在对它感到满意,我没有感觉到任何性能上的问题。有更多摩希经验的人会说这样做太可怕了,还是说这可能是我所能得到的最好的限制
编辑:
虽然我还没有关于这是否是一个好的方法的答案,但我可以确认这带来了两个隐藏的问题,我可以不建议你走这条路
158367420000
)转换为java字符串类型,则这些数字将不起作用。你可能以为你会得到“158364200000”,但实际上你得到的是“1.5836742E12”我被告知我在这里的编辑是错误的。我不确定它是否正确,但我们在这里讨论它我复制并修改了
KotlinJsonAdapter
,并从中删除了空值,并使用了默认值。它适用于您的TLDR不要使用此工厂案例@coltonidle@UmeshChhabra你能分享一个要点吗?如果有人想检查和评论副作用、bug,我已经做了一些修改etc@UmeshChhabra我还没有试过你的代码,但我快速看了一下。看起来真不错!也感谢所有这些测试!这肯定会在将来帮助很多人!试着检查一下:我已经复制并修改了KotlinJsonAdapter
,删除了其中的空值,并使用了默认值。它适用于您的TLDR不要使用此工厂案例@coltonidle@UmeshChhabra你能分享一个要点吗?如果有人想检查和评论副作用、bug,我已经做了一些修改etc@UmeshChhabra我还没有试过你的代码,但我快速看了一下。看起来真不错!也感谢所有这些测试!这肯定会在将来帮助很多人!请尝试检查以下内容:
class DefaultIfNullFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>,
moshi: Moshi): JsonAdapter<*>? {
val delegate = moshi.nextAdapter<Any>(this, type, annotations)
return object : JsonAdapter<Any>() {
override fun fromJson(reader: JsonReader): Any? {
val blob1 = reader.readJsonValue()
try {
val blob = blob1 as Map<String, Any?>
val noNulls = blob.filterValues { it != null }
return delegate.fromJsonValue(noNulls)
} catch (e: Exception) {
return delegate.fromJsonValue(blob1)
}
}
override fun toJson(writer: JsonWriter, value: Any?) {
return delegate.toJson(writer, value)
}
}
}
}