Warm tip: This article is reproduced from serverfault.com, please click

Is there any way to "hide" a Kotlin function from Retrofit annotation processor?

发布于 2020-11-28 15:03:55

I have a few interfaces that looks something like the following:

interface ApiInterface : Context.Element {
    @GET(Urls.url)
    suspend fun getSomeData(): Data
}

interface Context.Element {
    operator fun plus(context: Context): Context
}

I am trying to implement a Context implementation in similar way of the Kotlin CoroutineContext. As I am trying to add my Retrofit http interface as a Context.Element it ends up inheriting some other functions. The code compiles and runs fine until I call a function from my ApiInterface instance which inherits from Context.Element therefore doesn't have any @GET, @POST or any retrofit annotation.

If I run the following code:

val context = ApiInterfaceImpl()
context + DifferentApiInterfaceImpl()

I receive a Exception in thread "main" java.lang.IllegalArgumentException: HTTP method annotation is required (e.g., @GET, @POST, etc.). for method Context.plus.

I believe that if I am able to make the Retrofit annotation processor to skip the functions inherited from Context.Element this problem would be solved. Is there any way to to this? Any @Transient like annotation for functions? I tried to use @JvmSynthetic but no luck.

Questioner
admqueiroga
Viewed
0
esentsov 2020-11-29 03:22:45

The issue here is not in annotation processor, but in the way Retrofit works. It doesn't generate an implementation class, but creates a proxy object at runtime and this proxy object handles all method calls and routes them to the proper handler. So obviously it can't handle a non-service method. Also it's not clear how you would provide an implementation for that non-annotated method. So I would say it's currently impossible.

Edit: As you are using default method on interface to provide the implementation, it should generally work I believe, because Retrofit handles default methods separately. The issue here might be that Retrofit knows about java default methods only and by default kotlin does not use them (for compatibility with java 7 and below). So if you make the compiler generate java default method, it should work. Please check out this post for details.