moshi

Enum parsing fails with moshi and R8


I have the following dependencies:

moshi-codegen: 1.10.0
kotlin: 1.4.10
Android Gradle Plugin: 4.0.1
R8 is enabled in the build.

At runtime, i got the following stacktrace when Moshi tries to parse enums

java.lang.AssertionError: Missing field in e.f.a.k.c.b.a
        at com.squareup.moshi.StandardJsonAdapters$EnumJsonAdapter.<init>(SourceFile:246)
        at com.squareup.moshi.StandardJsonAdapters$1.create(SourceFile:67)
        at com.squareup.moshi.Moshi.adapter(SourceFile:141)
        at com.tsystems.tpay.data.client.models.ContactApiModelJsonAdapter.<init>(SourceFile:30)
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at com.squareup.moshi.internal.Util.generatedAdapter(SourceFile:553)
        at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(SourceFile:193)
        at com.squareup.moshi.Moshi.adapter(SourceFile:141)
        at com.squareup.moshi.Moshi.adapter(SourceFile:101)
        at com.squareup.moshi.Moshi.adapter(SourceFile:71)
        at com.squareup.moshi.CollectionJsonAdapter.newArrayListAdapter(SourceFile:52)
        at com.squareup.moshi.CollectionJsonAdapter$1.create(SourceFile:36)
        at com.squareup.moshi.Moshi.adapter(SourceFile:141)
        at com.squareup.moshi.Moshi.adapter(SourceFile:101)
        at p.z.a.a.a(SourceFile:91)
        at p.u.a(SourceFile:352)
        at p.u.b(SourceFile:335)
        at p.k.a(SourceFile:113)
        at p.k.a(SourceFile:82)
        at p.v.a(SourceFile:37)
        at p.u.a(SourceFile:192)
        at p.u$a.invoke(SourceFile:149)
        at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
        at $Proxy14.c(Unknown Source)
        at e.f.a.k.b.f$g.a(SourceFile:87)
        at i.b0.j.a.a.b(SourceFile:33)
        at j.a.v0.run(SourceFile:241)
        at j.a.g3.a.a(SourceFile:594)
        at j.a.g3.a.a(SourceFile:60)
        at j.a.g3.a$b.run(SourceFile:740)
     Caused by: java.lang.NoSuchFieldException: PERSONAL
        at java.lang.Class.getField(Class.java:1604)
        at com.squareup.moshi.StandardJsonAdapters$EnumJsonAdapter.<init>(SourceFile:240)

According to the README, i do not have to add R8 rules manually, but maybe enums are exceptions?


Solution

  • Yes enum should be treated a bit differently and there is currently a pending PR to update the README file (as of the time of writing) https://github.com/square/moshi/pull/1216.

    You have 2 options:

    1. Add @JsonClass(generateAdapter = false) on top of your enum definition.
    2. Add a proguard rule to keep your enum's fields e.g.,
    -keepclassmembers enum your.model.package.YourEnum {
        <fields>;
        **[] values();
    }
    

    Reason:

    According to the code here https://github.com/square/moshi/blob/0c85eae34af00ecbee46beaa5b25fb4af00fb9f2/moshi/src/main/resources/META-INF/proguard/moshi.pro#L10, Enum field names are used by the integrated EnumJsonAdapter. Also values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly.

    Also note on the same file that Moshi has generated a pre-made proguard rule which is inherited by your app:

    -keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
        <fields>;
        **[] values();
    }
    

    This rule is basically applied to all classes annotated by the @JsonClass annotation, so if you add the annotation (Option#1), your class would be covered by this rule.

    Alternatively if you don't want adding the annotation, you can add the rule specifically for your class aka Option#2.