retrofit
retrofit copied to clipboard
After enable R8 full mode getting ParameterizedType error
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)
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.
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
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?
You can just copy-paste the rules https://github.com/square/retrofit/issues/3751#issuecomment-1192043644 into your project.
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 😉
@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>
Things about Sandwich will be fixed in https://github.com/skydoves/sandwich/pull/103.
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)
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?
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?
Did you able to solve it?
@chiragthummar I just copied these rules into my project but I would still prefer a new Retrofit release 🙏🏼
Thanks you for your answer @svenjacobs
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
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.
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
@eury-fsl will try this and get back.
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 ----------
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
@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
@DarkAbhi Can you show me your rules and code for one of your APIs (the interface).
@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.
@DarkAbhi Do you have a custom CallAdapter set to retrofit?
@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)
After clearing cache and invalidating AS, it now worked :)
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.
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.
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
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.
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)
Update: Adding -dontwarn kotlin.coroutines.Continuation
to proguard's file solved the issue for me.