Liu Adoo
Liu Adoo

Reputation: 41

Moshi Json annotation does not work with proguard

I followed https://github.com/square/moshi to add gradle dependency on moshi and proguard rules, then I write code to verify.

data class Car(
    @Json(name = "low_speed")  val lowSpeed: Int,
    @Json(name = "high_speed") val highSpeed: Int
)
val moshi = Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()
val jsonAdapter = moshi.adapter(Car::class.java)

val json = "{\"low_speed\": 10, \"high_speed\": 20}"
val car = jsonAdapter.fromJson(json)

if (car != null) {
    Toast.makeText(this, "${car.lowSpeed}+${car.highSpeed}", Toast.LENGTH_LONG).show()
}

when I run it in debug mode, it displayed "10+20", which is expected, but when I run in release mode (which has proguard enabled), I saw "0+0".

My proguard-rules.pro file:

# Retain generic type information for use by reflection by converters     and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions

# Common Stuff to Keep
-keepattributes *Annotation*
-keepattributes JavascriptInterface

# OkHttp
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.ConscryptPlatform

# okIo
-dontwarn okio.**

#moshi
# JSR 305 annotations are for embedding nullability information.
-keepclasseswithmembers class * {
    @com.squareup.moshi.* <methods>;
}

-keep @com.squareup.moshi.JsonQualifier interface *

# Enum field names are used by the integrated EnumJsonAdapter.
# values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly
# Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi.
-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
    <fields>;
    **[] values();
}

#moshi-kotlin
-keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl

-keepclassmembers class kotlin.Metadata {
    public <methods>;
}

my build.gradle dependency:

// moshi
implementation("com.squareup.moshi:moshi:1.9.2")
implementation("com.squareup.moshi:moshi-kotlin:1.9.2")

// okhttp
implementation "com.squareup.okhttp3:okhttp:3.10.0"

I suppose I am missing something with moshi and proguard, but I really don't know what it is

Upvotes: 4

Views: 5135

Answers (3)

Sofien Rahmouni
Sofien Rahmouni

Reputation: 4927

There is several options to avoid obsfucating model data parsed by Moshi json :

  • @keep : Add this annotation
  • @field:JsonProperty(“fieldname”) : Add field annotation
  • Inherit a class which has rule to keep in Proguard
  • keep data class as all the data class : Add specfic rule -keep in proguard

And don't forget to add this important rule to make sure the input param class will not obsfucated :

-dontobfuscate

Upvotes: 0

kevinvanleer
kevinvanleer

Reputation: 1125

TLDR; Use the @Keep annotation to prevent minification of your target class.

My case was a little different from the one described by OP. My app was crashing when attempting to parse a JSON response with the moshi jsonAdapter.

val jsonAdapter = Moshi.Builder().add(KotlinJsonAdapterFactory()).build().let { moshi ->
    moshi.adapter(WeatherResponse::class.java)
}

...

val weatherResponse = response.body?.source()?.let { 
    jsonAdapter.nullSafe().fromJson(it) 
}

I resolved the issue by applying the @Keep annotation to the WeatherResponse class definition and all classes instantiated by WeatherResponse.

@Keep
data class Weather(
...

That seems to have resolved the issue for me.

Upvotes: 3

Lorenzo
Lorenzo

Reputation: 155

Try to add:

@JsonClass(generateAdapter = false)

AND add these lines to proguard:

-keepclassmembernames @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
    <fields>;
}

Credit -> https://github.com/square/moshi/issues/689

Upvotes: 0

Related Questions