Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service interface extending doesn't work with Proguard/R8 #3539

Open
ursusursus opened this issue Mar 26, 2021 · 6 comments
Open

Service interface extending doesn't work with Proguard/R8 #3539

ursusursus opened this issue Mar 26, 2021 · 6 comments

Comments

@ursusursus
Copy link

ursusursus commented Mar 26, 2021

Hi, since latest versions now support service interface subclassing, as to facilitate versioning, I did just so

interface ConfigApi {
    suspend fun configuration(): Response<ConfigurationResponse>
}

interface V1ConfigAp : ConfigApi {
    @GET("api/v1/config")
    override suspend fun configuration(): Response<ConfigurationResponse>
}

interface V2ConfigAp : ConfigApi {
    @GET("api/v2/config")
    override suspend fun configuration(): Response<ConfigurationResponse>
}

I'm on android. If run in debug, everything works.
If run with R8 turned on, at runtime I get

2021-03-26 18:10:06.503 22986-23211/foo.bar W/Default: HTTP method annotation is required (e.g., @GET, @POST, etc.).
        for method b.a
    java.lang.IllegalArgumentException: HTTP method annotation is required (e.g., @GET, @POST, etc.).
        for method b.a

If I explicitly keep the class -keep class foo.bar.V2ConfigApi { *; } it works

It appears R8 ignores the "implementing" interface V2ConfigApi (Its only reference is in a dagger module provider method, and nowhere else), and just uses the base one, which obviously doesn't have the annotations.

I can live with the keep rule for now, but it's footgunny, since almost nothing requires app level keep rules now
Is there a general rule to be extracted? (and then possibly merged into the library)

Android
AGP 4.1.2
Retrofit 2.9.0

@ursusursus
Copy link
Author

Although I'd naively expect this to already be that general rule

https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro#L9

@ursusursus
Copy link
Author

:/

@rumburake
Copy link

As a workaround we could annotate the base class too:

interface ConfigApi {
    @GET("api/v1/config")
    suspend fun configuration(): Response<ConfigurationResponse>
}

interface V1ConfigAp : ConfigApi {
    @GET("api/v1/config")
    override suspend fun configuration(): Response<ConfigurationResponse>
}


interface V2ConfigAp : ConfigApi {
    @GET("api/v2/config")
    override suspend fun configuration(): Response<ConfigurationResponse>
}

@JakeWharton
Copy link
Member

I need a project which reproduces the behavior in order to investigate.

@dmytroKarataiev
Copy link

@JakeWharton created a reproducible sample here: https://github.com/dmytroKarataiev/RetrofitProguard/tree/master

@Reginer
Copy link

Reginer commented Mar 8, 2023

-keep class kotlin.coroutines.Continuation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants