square / moshi

A modern JSON library for Kotlin and Java.
https://square.github.io/moshi/1.x/
Apache License 2.0
9.68k stars 758 forks source link

Kotlin data class with Retrofit2 proguard #717

Open Kisty opened 5 years ago

Kisty commented 5 years ago

Thanks for this great library!

I'm having trouble with keeping the names of the fieldsin Kotlin data classes with proguard. I tried using moshi-kotlin-reflect and moshi-kotlin-codegen with the KotlinJsonAdapterFactory but to no avail. It kept obfuscating the field names. Also, tried @Keep annotation on class and fields. Proguard keeps changing the field name to a instead of thingy.

import android.support.annotation.Keep
import com.squareup.moshi.JsonClass

@Keep
@JsonClass(generateAdapter = true)
data class AuthRequest(@Keep val thingy: String)

proguard.txt

-keep @kotlin.Metadata class uk.co.imagitech.learn2.iap.models.**
-keepclassmembers class com.squareup.moshi.JsonClass {
    public <methods>;
}

build.gradle

implementation 'com.squareup.moshi:moshi:1.7.0'
implementation 'com.squareup.moshi:moshi-kotlin:1.7.0'
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.7.0'

Also, I'm using Retrofit2.

Kisty commented 5 years ago

The problem is actually as I have a Request object with fields which stay constant. The fields don't show up in the JSON request:

import android.support.annotation.Keep
import com.squareup.moshi.JsonClass

@Keep
@JsonClass(generateAdapter = true)
internal data class VerifyPurchaseRequest(val purchaseToken: String) {
    @Keep val packageName: String = "com.example.thingy"
    @Keep val productId: String = "the_id"
}

It seems to be a problem with serialising the fields. It was working fine without proguard, however now it doesn't work without proguard enabled which is odd.

Kisty commented 5 years ago

I've found a workaround: use var instead of val as suggested in https://github.com/square/moshi/issues/590#issuecomment-401643704

As an aside, what JsonAdapterFactory should I be using? At the moment, I had to make my own for the generated adapters.

Kisty commented 5 years ago

I thought that the moshi-kotlin-codegen required the rules from moshi-kotlin, but that was unclear. Adding only the base rules works fine. Perhaps it would be better to either rename the artifact as moshi-kotlin-reflect or specify that for moshi-kotlin-codegen, only the base Moshi proguard rules are required.

README.md:

The moshi-kotlin artifact additionally requires the options from this file

shamo42 commented 5 years ago

Same issue here. It completely breaks all network calls with retrofit and moshi. Proguard rules don't help. I'll have to disable proguard until this is fixed.

thatsankur commented 5 years ago

Any Solution for this ?

ZacSweers commented 5 years ago

Hey folks - please link repro projects for issues, as we can't offer much guidance without repro cases

shoheikawano commented 4 years ago

Hi all,

I was using moshi-kotlin-codegen (version 1.9.2) for my personal project with R8 enabled. When I made a GET API request the app crashed with NoSuchMethodException.

The response class declaration is pretty similar to this:

@Keep
@JsonClass(generateAdapter = true)
class RepositoriesResponse(
    @Json(name = "total_count") val totalCount: Int,
    val items: List<RepositoryResponse> = emptyList()
)

I dug into the issue little bit and found out that having any response class declaration with default values causes this issue, and once removing those default values, the exception did not occur.

I made a sample repository for reproducing the issue. https://github.com/shoheikawano/MoshiGitHubSample

As I left a comment, removing the default value seems solving this issue.

By the way, maybe this is because of the simplicity of the sample project, but beside @Keep annotation, there is no proguard-rules setup needed to build this project with assembleRelease; the base moshi proguard rules seems just enough.

lrampazzo commented 4 years ago

Hi all,

the problem is releated to the dynamic loading of class kotlin.Metadata in com.squareup.moshi.internal.Util, which is removed by Proguard/R8 by default. Issue is already fixed by #1038 but not yet released.

Until then, as workaround, just add to your proguard file the following rule:

-keep class kotlin.Metadata

mdeandrea-mrmilu commented 2 years ago

If #1038 is released, can close this issue?