Moshi: Using Moshi 1.8.0 with R8 does not work with Json Qualifiers

Created on 28 Jan 2019  路  5Comments  路  Source: square/moshi

When we converted our project to use R8 our project started using the wrong Json adapter.

We have two qualifiers:

@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class HexNumber

@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DecimalNumber

We then use these two qualifiers for the JsonAdapters:

class HexNumberAdapter {
    @ToJson
    fun toJson(@HexNumber hexNumber: BigInteger): String = hexNumber.toHexString()

    @FromJson
    @HexNumber
    fun fromJson(hexNumber: String): BigInteger = hexNumber.hexAsBigInteger()
}

class DecimalNumberAdapter {
    @ToJson
    fun toJson(@DecimalNumber bigInteger: BigInteger): String = bigInteger.toString()

    @FromJson
    @DecimalNumber
    fun fromJson(decimalNumber: String): BigInteger = decimalNumber.toBigInteger()
}

This is the class that specifies that the field is a DecimalNumber so DecimalNumberAdapter should be the one converting the field.

@JsonClass(generateAdapter = true)
data class Test(
    @Json(name = "payment") @field:DecimalNumber val payment: BigInteger,
)

When we switched to R8 (from ProGuard) the adapter that is triggered is HexNumberAdapter. My theory is that @field:DecimalNumber is removed when R8 kicks in thus Moshi will use the first adapter added (HexNumberAdapter).

We have the rules defined in this file.

Moshi Version 1.8.0 (using codegen).

Most helpful comment

We are creating moshi the following way:

return Moshi.Builder()
            .add(HexNumberAdapter())
            .add(DecimalNumberAdapter())
            .build()

also after adding the keep for the annotations explicitly it worked again (this was not required by proguard):

-keep @interface pm.gnosis.heimdall.data.adapters.HexNumber
-keep @interface pm.gnosis.heimdall.data.adapters.DecimalNumber

All 5 comments

We are creating moshi the following way:

return Moshi.Builder()
            .add(HexNumberAdapter())
            .add(DecimalNumberAdapter())
            .build()

also after adding the keep for the annotations explicitly it worked again (this was not required by proguard):

-keep @interface pm.gnosis.heimdall.data.adapters.HexNumber
-keep @interface pm.gnosis.heimdall.data.adapters.DecimalNumber

Nothing else to be done here I think. These are used at runtime, so they need to be retained. Not sure why proguard didn't remove them compared to R8, as I expect it would as well unless it's trying to do some clever checks to guess if you're using it.

You could make a more general rule to keep all qualifiers via

-keep,allowobfuscation @com.squareup.moshi.JsonQualifier @interface * { *; }

Only the rule specified here worked for me after migrating to R8. I suggest updating documentation as the current rule for qualifiers: -keep @com.squareup.moshi.JsonQualifier interface * wasn't helpful for some reason.

You could make a more general rule to keep all qualifiers via

-keep,allowobfuscation @com.squareup.moshi.JsonQualifier @interface * { *; }

It works, but shouldn't the next line from proguard-rules.pro of Moshi work in this case?
-keep @com.squareup.moshi.JsonQualifier interface *

Nothing else to be done here I think. These are used at runtime, so they need to be retained. Not sure why proguard didn't remove them compared to R8, as I expect it would as well unless it's trying to do some clever checks to guess if you're using it.

You could make a more general rule to keep all qualifiers via

-keep,allowobfuscation @com.squareup.moshi.JsonQualifier @interface * { *; }

This rule worked for me as well, whereas the -keep @com.squareup.moshi.JsonQualifier interface * rule did not.

Was this page helpful?
0 / 5 - 0 ratings