moshi: Moshi-kotlin does not work with proguard
When ProGuard is enabled the call rawType.kotlin.primaryConstructor
in KotlinJsonAdapterFactory
returns null
so it exits early.
I created a sample repository here which demonstrates the issue: https://github.com/grandstaish/moshi-kotlin-reflection
The only way I can get Moshi to work currently is to uncomment this line in proguard (-keep class kotlin.** { *; }
). However, keeping literally everything in kotlin is going way overboard! Is there a better solution to this?
I have tried to figure this out for too long now and I’m going to have to pass this issue onto the experts, sorry! 😞
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 8
- Comments: 15 (7 by maintainers)
Commits related to this issue
- bugfix #453 Fix RandomWikipedia's bug. Fix #453. Overview Add ProGuard settings. See https://github.com/square/moshi/issues/345#issuecomment-337328427 — committed to toastkidjp/Yobidashi_kt by toastkidjp 5 years ago
- Proguard rule for Moshi reflect https://github.com/pusher/push-notifications-android/pull/101 enables moshi-kotlin reflection adapter which crashes if the kotlin.Metadata annotation is removed by pro... — committed to julioromano/push-notifications-android by julioromano 4 years ago
- Proguard rule for Moshi reflect https://github.com/pusher/push-notifications-android/pull/101 enables moshi-kotlin reflection adapter which crashes if the kotlin.Metadata annotation is removed by pro... — committed to julioromano/push-notifications-android by julioromano 4 years ago
- Update moshi-kotlin.pro In order to get moshi-kotlin working with reflection, while using R8, this line needs to be added. Maybe this line seams obvious, but it could save some hours to someone. ... — committed to Iljo/moshi by Iljo 4 years ago
Update to my previous comments: This issue doesn’t seem to be related to the enum, since it persisted after I got back to raw Strings. Only keeping the models solved the issue. Here are my proguard rules:
These may be overly conservative, but at least, my app works properly with these. I’m waiting for better proguard rules, if any are possible. Hope it helps anyone encountering the same issue!
@JakeWharton was right all along 😥:
The required rules for kotlin are:
Also it might be worth mentioning that you need to keep the constructors and fields of your model classes too:
Do you want me to create a PR to update the README.md?
Since my last comment, I have had to add a rule to keep all of my model class names too. This is because the fully qualified classname is kept as a String in the
@Metadata
annotation, and sometimeskotlin-reflect
will use it. For anyone interested, the rule looked like so:I also changed another rule in the README to be more specific:
So far this has been working, but I’ll comment in here if we find anything else.
Edit: @ktchernov you could also define your own annotation, and then define specific proguard rules to apply for classes with that annotation. That way you’ll still get some small amount of obfuscation + you’ll strip all the methods that aren’t being used.
Update for my last comment: I still use Moshi, but replaced
moshi-kotlin
withkotshi
, which plays fine with Proguard without special rules, dropping hundreds of kilobytes in the final apk.Keeping Kotlin meta data is not enough. And keeping all constructors and fields of model classes is really annoying to do. Unless you move all your model classes into one package.
I’m trialling a workaround to add the Android Support annotation
@Keep
on model classes.@Keep
has a rule of-keep @android.support.annotation.Keep class * {*;}
in the defaultproguard-android.txt
. May be enough to do the trick.Are there any workarounds for this? Using
moshi-kotlin
and ProGuard is a pretty common occurrence… I keep getting a dreadedIllegalArgumentException: Unable to create converter for class (...)
exception when ProGuard is enabled.There are two factors for proguard rules.
1 - rules for kotlin-reflect. These have been historically finicky, but kotlin 1.4 will finally ship with minimal rules embedded directly in the kotlin-reflect artifact. These ensure that kotlin-reflect’s machinery works, and should be the same for all users (hence them being bundled in the kotlin-reflect jar now). But this alone is not enough!
2 - rules for reflective serialization. This is the same problem that has always existed with reflective serialization and you have to keep any classes or fields/properties that you want to reflectively serialize. There are unique per application because they’re your models. Common patterns for this include keeping a common models package with wildcards or denoting them with a marker annotation and keeping anything annotated with it.
For those that have consistent reproduction cases, try with Kotlin 1.4 (specifically with kotlin-reflect 1.4 or copy the rules from here) and ensure your proguard rules separately have rules for your reflectively serialized models.
If you still have issues with both, report back with a minimally reproducible sample project link. My hope though is that this is resolved with the combination of first-party rules and ensuring your own project’s rules are correct.
@marcosalis Just above your message, there’s one, yes. Now, you can also use moshi kotlin codegen, see the README.
Keep Kotlin’s metadata annotation. That’s all that should be needed.
On Mon, Aug 28, 2017 at 1:02 PM Jesse Wilson notifications@github.com wrote: