square / retrofit

A type-safe HTTP client for Android and the JVM
https://square.github.io/retrofit/
Apache License 2.0
42.82k stars 7.29k forks source link

After enable R8 full mode getting ParameterizedType error #3751

Closed NG-Gaurav closed 5 months ago

NG-Gaurav commented 2 years ago

Accessing hidden method Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V (greylist, reflection, allowed) 16:09:29.013 W java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 16:09:29.014 W at retrofit2.HttpServiceMethod.parseAnnotations(SourceFile:46) 16:09:29.014 W at retrofit2.ServiceMethod.parseAnnotations(SourceFile:39) 16:09:29.014 W at retrofit2.Retrofit.loadServiceMethod(SourceFile:202) 16:09:29.014 W at retrofit2.Retrofit$1.invoke(SourceFile:160) 16:09:29.014 W at java.lang.reflect.Proxy.invoke(Proxy.java:1006) 16:09:29.014 W at $Proxy6.generateAnonymousAuthTokenAsyn(Unknown Source)

marcoscostaanddev commented 1 year ago

I'm facing a very similar issue. When i fire up the request with proguard enabled in R8 fullmode this exception raises:

java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType at retrofit2.HttpServiceMethod.parseAnnotations(SourceFile:46) at retrofit2.ServiceMethod.parseAnnotations(SourceFile:39) at retrofit2.Retrofit.loadServiceMethod(SourceFile:202) at retrofit2.Retrofit$1.invoke(SourceFile:160) at java.lang.reflect.Proxy.invoke(Proxy.java:1006)

I believe that probably is a bug with R8 fullmode enabled. I'm using retrofit 2.9.0 + okHttp3 4.2.0 + square-gson-converter 2.6.1 + kotlin coroutines.

Goooler commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files.

https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.


EDIT: Now you can just simplify use these

https://github.com/square/retrofit/blob/2f12836535128a3d0e8fe8a2ac0b46413e6a28a0/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L38-L48

svenjacobs commented 1 year ago

Now that Android Studio Flamingo with AGP 8.0 enabled R8 full mode by default, I'm facing the same issue.

Could you please release a new version of Retrofit with the updated consumer rules?

Goooler commented 1 year ago

You can just copy-paste the rules https://github.com/square/retrofit/issues/3751#issuecomment-1192043644 into your project.

svenjacobs commented 1 year ago

You can just copy-paste the rules #3751 (comment) into your project.

I know, but not having to maintain R8 rules for third-party libraries is much nicer 😉

proninyaroslav commented 1 year ago

@Goooler It doesn't actually work, at least for me with AGP 8.0. After adding this proguard lines I get a slightly different error. Perhaps the reason is in the sandwich library, but I'm not sure:

 java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Call<com.skydoves.sandwich.ApiResponse>
                     for method ComicVineService.issues
                    at retrofit2.Utils.methodError(SourceFile:47)
                    at retrofit2.HttpServiceMethod.parseAnnotations(SourceFile:394)
                    at retrofit2.Retrofit.loadServiceMethod(SourceFile:31)
                    at retrofit2.Retrofit$1.invoke(SourceFile:45)
                    at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
                    at $Proxy9.issues(Unknown Source)
                        ...
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
                    at com.skydoves.sandwich.adapters.ApiResponseCallAdapterFactory.get(SourceFile:53)
                    at retrofit2.Retrofit.callAdapter(SourceFile:33)
                    at retrofit2.HttpServiceMethod.parseAnnotations(SourceFile:375)
                    ... 41 more
 @GET("issues?format=$FORMAT&field_list=${Fields.Issues}")
    @JvmSuppressWildcards
    suspend fun issues(
        @Query("api_key") apiKey: String,
        @Query("offset") offset: Int,
        @Query("limit") limit: Int,
        @Query("sort", encoded = true) sort: ComicVineSort?,
        @Query("filter[]", encoded = true) filter: List<ComicVineFilter>?,
    ): ApiResponse<IssuesResponse>
Goooler commented 1 year ago

Things about Sandwich will be fixed in https://github.com/skydoves/sandwich/pull/103.

jafar-alrashid commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files.

https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

Hi I have added these rules to my project and still getting the same error, did this work for anyone?

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:46) at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39) at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202) at retrofit2.Retrofit$1.invoke(Retrofit.java:160) at java.lang.reflect.Proxy.invoke(Proxy.java:1006)

G00fY2 commented 1 year ago

The R8 FAQ states the following:

Attributes (such as Signature) and annotations are only kept for classes, methods and fields which are matched by keep rules even when -keepattributes is specified. The weakest rule that will keep annotations and attributes is -keep[classmembers],allowshrinking,allowoptimization,allowobfuscation,allowaccessmodification class-specification Additionally, for attributes describing a relationship such as InnerClass and EnclosingMethod, non-compat mode requires both endpoints being kept.

Does anyone know why the rules in retrofit only contain keep,allowobfuscation,allowshrinking but missing allowoptimization and allowaccessmodification?

The ProGuard documentation states that allowaccessmodification should probably not be used for libraries:

Counter-indication: you probably shouldn't use this option when processing code that is to be used as a library, since classes and class members that weren't designed to be public in the API may become public.

But what about the allowoptimization?

chiragthummar commented 1 year ago

Now that Android Studio Flamingo with AGP 8.0 enabled R8 full mode by default, I'm facing the same issue.

Could you please release a new version of Retrofit with the updated consumer rules?

Did you able to solve it?

svenjacobs commented 1 year ago

Did you able to solve it?

@chiragthummar I just copied these rules into my project but I would still prefer a new Retrofit release 🙏🏼

chiragthummar commented 1 year ago

Thanks you for your answer @svenjacobs

DarkAbhi commented 1 year ago

Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).

-keep,allowobfuscation,allowshrinking interface retrofit2.Call -keep,allowobfuscation,allowshrinking class retrofit2.Response

With R8 full mode generic signatures are stripped for classes that are not

kept. Suspend functions are wrapped in continuations where the type argument

is used.

-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

Same, have you found the issue? This is my exact issue if it helps - https://stackoverflow.com/questions/76118721/r8-full-mode-throws-class-cast-exception-agp-8-0

DarkAbhi commented 1 year ago

ChatGPT gave me this as the answer

The java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType error can occur with Retrofit and Moshi when using R8 full mode because R8 removes the generic type information during the code optimization process. Here's how you can fix this issue:

Add the following Proguard/R8 rule to your proguard-rules.pro file to keep the generic type information:

-keepattributes Signature

If you're using Moshi, add the following Proguard/R8 rule to your proguard-rules.pro file to keep the classes that are used for JSON serialization and deserialization:

-keepclassmembers class com.example.MyClass {
  @com.squareup.moshi.FromJson *;
  @com.squareup.moshi.ToJson *;
}

Replace com.example.MyClass with the name of your class.

If you're using Kotlin, add the following Proguard/R8 rule to your proguard-rules.pro file to keep the Kotlin metadata:

-keepclassmembers class com.example.MyClass {
  kotlin.Metadata <fields>;
}

Replace com.example.MyClass with the name of your class.

If you're still experiencing the issue, you can try using the TypeToken class from the Gson library instead of the ParameterizedType class. To use TypeToken, replace the following code:

Type type = new TypeToken<List<MyClass>>(){}.getType();

with:

Type type = Types.newParameterizedType(List.class, MyClass.class);

Note that you'll need to add the following dependency to your build.gradle file:

implementation 'com.google.code.gson:gson:2.8.9'

Finally, if you're using a custom Moshi JsonAdapter, you can try adding the @JsonClass(generateAdapter = true) annotation to your data class to generate the adapter at compile-time. This can help to avoid issues with R8. For example:

@JsonClass(generateAdapter = true)
data class MyClass(val name: String)

These steps should help you to resolve the java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType error when using Retrofit and Moshi with R8 full mode.

eury-fsl commented 1 year ago

If any of you are using a custom sealed class to represent your API calls state, make sure you include that, as done in the sandwich.pro file in this PR. Your final rules can look like:

# https://github.com/square/okhttp/blob/339732e3a1b78be5d792860109047f68a011b5eb/okhttp/src/jvmMain/resources/META-INF/proguard/okhttp3.pro#L11-L14
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**

# TODO: Waiting for new retrofit release to remove these rules
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

-keep,allowobfuscation,allowshrinking class com.your.company.YourCustomSealedClass
DarkAbhi commented 1 year ago

@eury-fsl will try this and get back.

chiragthummar commented 1 year ago

My Working Solutions

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

-keep class com.google.gson.reflect.TypeToken
-keep class * extends com.google.gson.reflect.TypeToken
-keep public class * implements java.lang.reflect.Type

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

##---------------End: proguard configuration for Gson  ----------
StylianosGakis commented 1 year ago

If any of you are using a custom sealed class to represent your API calls state, make sure you include that, as done in the sandwich.pro file in this PR. Your final rules can look like:

# https://github.com/square/okhttp/blob/339732e3a1b78be5d792860109047f68a011b5eb/okhttp/src/jvmMain/resources/META-INF/proguard/okhttp3.pro#L11-L14
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**

# TODO: Waiting for new retrofit release to remove these rules
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

-keep,allowobfuscation,allowshrinking class com.your.company.YourCustomSealedClass

Yup, when using https://github.com/arrow-kt/arrow-integrations/tree/main/arrow-integrations-retrofit-adapter arrow adapter which turns the response into and arrow.core.Either<>

I had to add exactly what was said above + -keep,allowobfuscation,allowshrinking class arrow.core.Either and it now works

DarkAbhi commented 1 year ago

@eury-fsl will try this and get back.

Okay this doesn't work I'm convinced I've got something to deal with Moshi.

This is my issue if anyone has a clue, thanks

Github issue - https://github.com/square/retrofit/issues/3751#issuecomment-1515817159 Stackoverflow - https://stackoverflow.com/questions/76118721/r8-full-mode-throws-class-cast-exception-agp-8-0

eury-fsl commented 1 year ago

@DarkAbhi Can you show me your rules and code for one of your APIs (the interface).

DarkAbhi commented 1 year ago

@eury-fsl here, this is my proguard

-keep class  com.iku.community_chat.data.room.entity.** { *; }
-keep class androidx.appcompat.widget.** { *; }
#Jsoup
-keep public class org.jsoup.** {
public *;
}
-keepnames class com.iku.user.profile.data.room.models.** { *; }
-keepnames class com.iku.community_courses.data.room.entity.** { *; }
-keeppackagenames org.jsoup.nodes

# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keep,allowobfuscation,allowshrinking class com.squareup.moshi.JsonAdapter

My ApiService

interface IkuApiService {
/**
     * Check if email exists
     *
     * @param email
     * @param authorization
     * @return
     */
    @FormUrlEncoded
    @POST("emailcheck")
    suspend fun checkIfEmailExists(
        @Field("email") email: String,
        @Tag authorization: AuthorizationType = AuthorizationType.NONE,
    ): EmailCheckModel

I have tried to add various rules to try out, this is what it is for now - https://pastebin.com/zJPcJFYT Also trying out @Keep on my models and apiService.

eury-fsl commented 1 year ago

@DarkAbhi Do you have a custom CallAdapter set to retrofit?

DarkAbhi commented 1 year ago

@eury-fsl No. This is how I provide my retrofit instances

@Provides
    @Singleton
    @Keep
    fun getIkuRetrofit(moshi: Moshi, okHttpClient: OkHttpClient): IkuApiService {
        return Retrofit.Builder()
            .baseUrl(Constants.IKU_BASE_URL)
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .client(okHttpClient)
            .build()
            .create(IkuApiService::class.java)
    }

    @Provides
    @Singleton
    @Keep
    fun getIkuAuthApiRetrofit(
        moshi: Moshi,
        @Named("for_auth") okHttpClient: OkHttpClient,
    ): IkuAuthApiService {
        return Retrofit.Builder()
            .baseUrl(Constants.IKU_BASE_URL)
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .client(okHttpClient)
            .build()
            .create(IkuAuthApiService::class.java)
DarkAbhi commented 1 year ago

After clearing cache and invalidating AS, it now worked :)

skhaz commented 1 year ago

Even putting the lines below on Proguard:

# -dontwarn kotlin.coroutines.Continuation
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**

# TODO: Waiting for new retrofit release to remove these rules
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

I still have the issue

Missing class kotlin.coroutines.Continuation (referenced from: java.lang.Object retrofit2.HttpServiceMethod$SuspendForBody.adapt(retrofit2.Call, java.lang.Object[]) and 2 other contexts)

My project doesn't uses Kotlin, it is pure Java 1.8, and it was working before.

examgoal commented 1 year ago

Even putting the lines below on Proguard:

# -dontwarn kotlin.coroutines.Continuation
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**

# TODO: Waiting for new retrofit release to remove these rules
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

I still have the issue

Missing class kotlin.coroutines.Continuation (referenced from: java.lang.Object retrofit2.HttpServiceMethod$SuspendForBody.adapt(retrofit2.Call, java.lang.Object[]) and 2 other contexts)

My project doesn't uses Kotlin, it is pure Java 1.8, and it was working before.

it's a issue with R8 full mode not with java version and with new version of android studio R8 full mode is enabled by default.

android.enableR8.fullMode=false

add this line to your gradle.properties file and it will be working perfectly.

StylianosGakis commented 1 year ago

it's a issue with R8 full mode not with java version and with new version of android studio R8 full mode is enabled by default. android.enableR8.fullMode=false

Full mode is there for a reason though. Don't opt out of it when the fix is simply to add a couple more rules to your proguard file

PhilipDukhov commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files.

https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

Wonder why it stopped getting rules from the library - adding these rules manually solved the issue to me.

skhaz commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files. https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

Wonder why it stopped getting rules from the library - adding these rules manually solved the issue to me.

Even adding these rules, doesn't worked for me (I'm using Java, not Kotlin)

skhaz commented 1 year ago

Update: Adding -dontwarn kotlin.coroutines.Continuation to proguard's file solved the issue for me.

aniqueazhar commented 1 year ago

Mixing these 2 worked for me. New Android Studio ( Android Studio Flamingo | 2022.2.1 Patch 1)

https://github.com/square/retrofit/issues/3751#issuecomment-1525914941

https://github.com/square/retrofit/issues/3751#issuecomment-1192043644

Hessam-Emami commented 1 year ago

Update: Adding -dontwarn kotlin.coroutines.Continuation to proguard's file solved the issue for me.

How would adding -dontwarn solve your problem? it just doesn't fail the build and swallows the issue imo. Haven't you face any runtime issue on your prod build??

skhaz commented 1 year ago

@Hessam-Emami it compiles, but it fails when open on the device.

1priyank1 commented 1 year ago

Adding below lines in proguard-rules.pro file, fixed the issue for me.

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response

# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
Ethan1983 commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files.

https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

FYI, had to add this to consumer-rules.pro of the module exposing retrofit APIs in Multi module project.

falgunirana2022 commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files.

https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

FYI: This solution working for me. Thank you.

errysuprayogi commented 1 year ago

New proguard rules added but not published yet, you can add these rules to your proguard-rules files. https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L34-L41

See #3579 & #3598.

FYI: This solution working for me. Thank you.

Not work for me :(

WesleyBatista commented 1 year ago

This is what worked for me:


-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
-repackageclasses

# Firebase  https://github.com/firebase/firebase-android-sdk/issues/4900
-keep public class com.google.firebase.** { *;}
-keep class com.google.android.gms.internal.** { *;}
-keepclasseswithmembers class com.google.firebase.FirebaseException

# https://github.com/square/retrofit/issues/3751#issuecomment-1564410089
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# https://github.com/google/gson/commit/43396e45fd1f03e408e0e83b168a72a0f3e0b84e#diff-5da161239475717e284b3a9a85e2f39256d739fb7564ae7fda7f79cee000c413
-keepclasseswithmembers,allowobfuscation,includedescriptorclasses class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

note the includedescriptorclasses.

johngray1965 commented 1 year ago

The suggestions above fixed all but one of my issues, I have a retrofit call that's defined as follow: @POST("/v2/request/{filename}") suspend fun requestBlah( @Header("Content-Type") contentType: String?, @Path("filename") filename: String?, @Body data: RequestBody? ): ResponseBody I still get a ClassCastException on that one.

johngray1965 commented 1 year ago

Adding: -keep,allowobfuscation,allowshrinking class okhttp3.RequestBody -keep,allowobfuscation,allowshrinking class okhttp3.ResponseBody fixed my remaining problem.

VicV commented 1 year ago

Anyone have this issue with Jackson? Clearly GSON was a known issue but i'm struggling with similar issues

JakeWharton commented 1 year ago

All reflection-based serialization libraries will exhibit problems that require rules to correct.

VicV commented 1 year ago

Yeah got it.

Anyone searching for a fix for the jackson error of java.lang.IllegalArgumentException: Internal error: TypeReference constructed without actual type information when R8 is enabled in your project when using AGP 8.0.2, this thread has the details ^

MalikHamidJaved commented 12 months ago

Still getting the issue after upgrading to gradle 8.0.2 as well.

Used these progaurd rules.

Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).

-keep,allowobfuscation,allowshrinking interface retrofit2.Call -keep,allowobfuscation,allowshrinking class retrofit2.Response

With R8 full mode generic signatures are stripped for classes that are not

kept. Suspend functions are wrapped in continuations where the type argument

is used.

-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

Not working for me.

digrec commented 11 months ago

This is what worked for me:


-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
-repackageclasses

# Firebase  https://github.com/firebase/firebase-android-sdk/issues/4900
-keep public class com.google.firebase.** { *;}
-keep class com.google.android.gms.internal.** { *;}
-keepclasseswithmembers class com.google.firebase.FirebaseException

# https://github.com/square/retrofit/issues/3751#issuecomment-1564410089
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# https://github.com/google/gson/commit/43396e45fd1f03e408e0e83b168a72a0f3e0b84e#diff-5da161239475717e284b3a9a85e2f39256d739fb7564ae7fda7f79cee000c413
-keepclasseswithmembers,allowobfuscation,includedescriptorclasses class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

note the includedescriptorclasses.

With AGP 8.1, after adding these rules pointed out by Goooler, the missing piece for me was this includedescriptorclasses modifier on the SerializedName annotation rule. Thanks @WesleyBatista!

-keepclasseswithmembers,allowobfuscation,includedescriptorclasses class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

Note that I'm already keeping all my API data classes anyway, that's probably related.

But it's possible that includedescriptorclasses modifier is not needed once you add all the missing Gson rules. Also check all your Retrofit rules.

VicV commented 11 months ago

For anyone using jackson googling for this error:

java.lang.IllegalArgumentException: Internal error: TypeReference constructed without actual type information

Read this issue.

On Fri, Jul 7, 2023 at 12:50 PM Jake Wharton @.***> wrote:

All reflection-based serialization libraries will exhibit problems that require rules to correct.

— Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/3751#issuecomment-1625682851, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJ5WJNWABBYCL33CWJ66M3XPA45HANCNFSM5274ZGRQ . You are receiving this because you commented.Message ID: @.***>

ravibpatel commented 11 months ago

Combining officialy commited proguard rules with @digrec's solution worked for me.

# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# If a class is used in some way by the application, and has fields annotated with @SerializedName
# and a no-args constructor, keep those fields and the constructor
# Based on https://issuetracker.google.com/issues/150189783#comment11
# See also https://github.com/google/gson/pull/2420#discussion_r1241813541 for a more detailed explanation
-if class *
-keepclasseswithmembers,allowobfuscation,allowoptimization class <1> {
  <init>();
  @com.google.gson.annotations.SerializedName <fields>;
}
Del-S commented 10 months ago

So fix for me was to use this rule from retrofit2.pro

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

And remove allowshrinking from it. Not really sure why. I guess it removed the functions because it seen them as unused? It might be becuase the Interface is provided using Hilt. But all of the functions are used in code so I don't know.

Now I have the rule as follow and it works:

# Retain service method parameters when optimizing.
-keep,allowobfuscation,allowoptimization interface * {
    @retrofit2.http.* <methods>;
}

Project is multimodule with Hilt as DI and Moshi as Json convertor. Example of our interface is like this:

internal interface AuthRestApi {

    @POST("main/users/login")
    suspend fun login(
        @Header(NetworkConstant.Header.HEADER_ACCEPT) endpointVersion: String = NetworkConstant.createEndpointVersion(),
        @Body request: LoginUserRequest
    ): Response<LoginResponse>
}
ariefzuhri commented 9 months ago

If you have tried all the solutions above and still haven't fixed the issue yet, make sure you have defined this line in every buildTypes configuration where minifyEnabled true.

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

I resolved this issue by adding the rule from retrofit2.pro to proguard-rules.pro and defining proguardFiles in my debug build type.

# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit

# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*

# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>

# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response

Edited: If you're using Gson (or a third-party library that depends on Gson) and encounter this new issue: java.lang.IllegalStateException: TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved. Try adding this rule:

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
svenjacobs commented 9 months ago

Now that Android Studio Flamingo with AGP 8.0 enabled R8 full mode by default, I'm facing the same issue.

Could you please release a new version of Retrofit with the updated consumer rules?

I'm sorry to ask again but is there a reason why no new version of Retrofit has been released in the past three years? Is this project still maintained?