I've recently started using Moshi for my Android app and I'm curious to know more about what the annotation @JsonClass(generateAdapter = true) really does.

示例数据类:

data class Person(
    val name: String
)

我可以按如下方式序列化/反序列化这个类:

val moshi: Moshi = Moshi.Builder().build()
moshi.adapter(Person::class.java).toJson(Person())

I'm not using the @JsonClass annotation here and hence codegen won't kick in.

My question is, why and when do I need to use @JsonClass(generateAdapter = true)

推荐答案

Earlier versions of Moshi didn't support "codegen", so they completely relied on reflection (i.e., the ability to introspect classes at runtime). However, that could be a problem for applications that require very high performance so they've added a "codegen" capability that takes advantage of annotation processing. Basically that allows generating code at compilation time, so they can perform serialisation/deserialisation without using reflection.

为了启用代码生成功能,您还需要启用Kapt,它是Kotlin注释处理器,否则不会进行注释处理.

Here you'll find how to enable and configure Kapt, and here you'll find how to set up Moshi codegen dependencies.


编辑

在您添加到问题中的代码片段中,Moshi使用ClassJsonAdapter来序列化您的对象.该适配器利用反射查找所有字段并创建JSON字符串(您可以看到该类从java.lang.reflect导入内容).

另一方面,Moshi为你的班级编写了generates a JsonAdapter代代码.例如,让Moshi为您的Person类创建适配器将产生以下结果:

// Code generated by moshi-kotlin-codegen. Do not edit.
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import java.lang.NullPointerException
import kotlin.String

class PersonJsonAdapter(moshi: Moshi) : JsonAdapter<Person>() {
    private val options: JsonReader.Options = JsonReader.Options.of("name")

    private val stringAdapter: JsonAdapter<String> =
            moshi.adapter<String>(String::class.java, kotlin.collections.emptySet(), "name")

    override fun toString(): String = "GeneratedJsonAdapter(Person)"

    override fun fromJson(reader: JsonReader): Person {
        var name: String? = null
        reader.beginObject()
        while (reader.hasNext()) {
            when (reader.selectName(options)) {
                0 -> name = stringAdapter.fromJson(reader) ?: throw JsonDataException("Non-null value 'name' was null at ${reader.path}")
                -1 -> {
                    // Unknown name, skip it.
                    reader.skipName()
                    reader.skipValue()
                }
            }
        }
        reader.endObject()
        var result = Person(
                name = name ?: throw JsonDataException("Required property 'name' missing at ${reader.path}"))
        return result
    }

    override fun toJson(writer: JsonWriter, value: Person?) {
        if (value == null) {
            throw NullPointerException("value was null! Wrap in .nullSafe() to write nullable values.")
        }
        writer.beginObject()
        writer.name("name")
        stringAdapter.toJson(writer, value.name)
        writer.endObject()
    }
}

As a result, when you ask for an adapter for Person, Moshi will use the generated PersonJsonAdapter instead of the ClassJsonAdapter.

prize

Moshi uses reflection to instantiate the generated adapter (which then gets cached, so that it gets reused next time you ask for an adapter for the same class), so that you don't need to add any extra code at all if you want to use the codegen functionality.

Kotlin相关问答推荐

如何将时间值格式化为00:00和00:00:00 Kotlin?""""

Kotlin是否针对范围和进度优化sum()?

为什么可组合对象看似无状态(唯一传递的参数是函数,而不是状态),但会进行重组

为什么使用 return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } 时无法获得单例?

为什么 Kotlin main 函数需要 @JVMStatic 注解?

为什么 Kotlin 在 sumOf 函数 lambda 中默认不将数字视为Int?

为什么 KFunction2 在 Kotlin 中不是可表示类型?

添加 Kapt 插件后 - 执行 org.jetbrains.kotlin.gradle.internal.KaptExecution 时发生故障

在 APK META-INF/library_release.kotlin_module 中复制的重复文件

调用单元测试验证伴随对象方法

变量后的Android问号

ActivityOptions.makeSceneTransitionAnimation 在具有多个视图的 kotlin 中不起作用

如何在 Spring WebFlux 的响应正文中流式传输二进制数据

Kotlin val difference getter override vs assignment

在Kotlin中为Android编写库会有开销吗?

Android Kotlin 创建类实现 Parcelable 在 writeToParcel 方法的 override中给出错误

保存对象时未填充 Spring Boot JPA@CreatedDate @LastModifiedDate

Kotlin Flow 收集后无法执行代码

是否可以在不使用class的情况下将 Mockito 与 Kotlin 一起使用?

Kotlin - 为什么我会得到 KotlinNullPointerException