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.
Example data class:
data class Person(
val name: String
)
I'm able to serialise/de-serialise this class as follows:
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)
This is sort of three questions
Code gen is useful as a compile-time alternative to the reflective moshi-kotlin. Both of them are useful because they natively understand Kotlin code and its language features. Without them, Moshi would not be able to understand Kotlin nullability, default values, and much more. There are cases where Moshi works by coincidence with just standard Java reflection, your example above is one of them. This is super error prone though, and in Moshi 1.9 these will be rejected and require either a generated adapter or kotlin-reflect.
Code gen is an annotation processor that looks for classes annotated with @JsonClass(generateAdapter = true)
. It generates an optimized streaming adapter for each annotated class. These adapters are Kotlin themselves and thus capable of leveraging Kotlin language features that support the target class. At runtime, Moshi reflectively looks up the generated adapter with a very simple known name suffix, which allows these adapters to Just Work without manual adapter registration.
You can find more info on both 1 and 2 in my blog post about it when it was released: https://www.zacsweers.dev/exploring-moshis-kotlin-code-gen/
You should use moshi-kotlin or code gen any time you are trying to serialize a Kotlin class with Moshi without your own custom adapter. Reflection will have no build time overhead but be far slower at runtime while also incurring a large binary size cost due to kotlin-reflect and cannot be safely obfuscated. Code gen incurs a build time cost but is extremely fast at runtime with minimal binary size cost and mostly obfuscation-safe. It's up to you which of these is better suited to your use case! You can also use a combination, such as reflection in debug builds and code gen just for release builds.