Moshi Kotlin Gotchas

Moshi 1.5 added @Json annotation support for Kotlin classes. It's a great addition for Kotlin projects and has been working really well for me. I'd just like to share three tips when working with Moshi Kotlin.

No generics support yet

Resovling generics types is still working in progress. AutoValue and its Moshi extension is the best alternative if you have such a need.

ProGuard

If it's unfortunate that your project has to use ProGuard in the release apk, there might be times a misconfiguration will surprise you, like some fields just gone missing. There are already many issues opened with people posting different workarounds. The rule stated in the README has worked for me until I bumped up Kotlin version to 1.50. And by the end of the day, we basically had to keep everything from kotlin.Metadata and all the model classes. :(

-keep class kotlin.Metadata { *; }
-keep class org.aaronhe.api.** { *; }

And if you are using Kotlin reflect 1.2, there's little extra configraution you may need to add: -keep public class kotlin.reflect.jvm.internal.impl.builtins.* { public *; }.

Adapter creation is expensive(for the first time)

Moshi Kotlin has a depdency on kotlin-reflect because it needs some extra information about the class, like what fields are being annotated, what's value of the @Json annotation etc. This transitive depedency will increase the apk size a little bit. If you are developing for Android, you might also need to be aware of when to call Moshi#adapter for kotlin classes. In order to get the information Moshi needs, Moshi has to get a hold of the primary constutor. However that's an expensive call because KClass#primaryConstructor will in-turn call getResourcesAsStream which could take 2 seconds on a Nexus 4 device running KitKat. Fortunately, Moshi caches generated adapters, so only the first time creation takes a performance hit.

I discovered this with the help from NimbleDroid. It was actually caused by a class having an adapter as its member variable and being injected at the application class. So the application startup time surffered from this. Making the adapter lazily initlaized was the easist fix.

There's also an interesting project called kotshi which uses annotation processing to generate Moshi adapters for Kotlin data classes. I haven't used this in production yet. But it looks very promising.