square / retrofit

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

Allow to configure retrofit to allow API interfaces to extend interfaces #504

Closed deigote closed 5 years ago

deigote commented 10 years ago

The comment:

// Prevent API interfaces from extending other interfaces. This not only avoids a bug in
// Android (http://b.android.com/58753) but it forces composition of API declarations which is
// the recommended pattern.

in:

https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/Utils.java

Sounds rather arbitrary. I think it should be configurable at the very least.

I for example have something very similar to the following.

A base response class:

class GenericResponse {
   Boolean success
}

and an interface that defines how my API needs to be accessed:

interface GenericAPI<R extends GenericResponse> {
   void obtainData(
      String name, String version, Map<String, String> parameters, Callback<R> callback
   )
}

I latter extend that interface with some specific API like:

interface GetUsersAPI extends GenericAPI<UsersResponse> {
   @GET("/dataAPI/{version}/{name}")
   void obtainData(
      @Path("name") String name,
      @Path("version") String version,
      @QueryMap Map<String, String> parameters,
      Callback<UsersResponse> callback
   )
}

being UsersResponse an extension of GenericResponse. With something like that, I can implement an abstract client like:

abstract class GenericClient<R extends GenericResponse, C extends GenericConnector> implements Callback<R> { 

   protected void doRequest(
      Class<C> apiDefinition, 
      String name, String version, 
      Map<String, Object> params
   ) { 
      new RestAdapter.Builder().build().create(apiDefinition).obtainData(
         name, version, params, this
      )
   }
}

That client can work with any of my APIs, avoiding code duplication while having typing enforced by the compiler using generics. It can deal with any obtainData connector and with the common parts of every response. When implemented by a concrete class, thanks to the use of generics and inheritance, the data is transformed to the proper specific response class and when using an IDE with generics support (any, I guess :) is very convenient to use every method with the signature automatically transformed to the concrete classes declared by the implementor class.

I understand that composition is better for many things, but I don't see how to work with a generic connector the way I'm doing it, being able to assume that every connector will have an obtainData with the given parameters and having that enforced by the compiler.

I'm not saying is not possible - I'm saying I don't know how, and the restriction I'm finding is, in my opinion, quite poorly explained.

I think something whose reason to be is something as arguable as "composition is the only possible, good way" should be configurable at least.

JakeWharton commented 10 years ago

At this point I would ask why are you even using Retrofit? It seems like you are gaining almost nothing and it arguably is more in your way. For whatever solution you are trying to achieve it seems like a purpose built solution will be more flexible and probably less code (or equal but more clear code) wouldn't you think?

Retrofit is not meant to solve all use cases and it really sounds like you are fighting to shove a use case into it that is fundamentally opposed to where it currently stands.

deigote commented 10 years ago

@JakeWharton I just exposed one of my use cases :), which I didn't build like that from the beginning - I started writing some interfaces, playing with them a bit by writing some clients and some model classes, then got into the refactor and eliminate duplicated code fun until I ended up with something I was satisfied with: next programmer to use my "framework" will be guided by the compiler/IDE into what she needs to program and which data-types it should deal with

I really like Retrofit so far, they way APIs are exposed as clean, annotated interfaces is very neat. I don't see how trying to "abstract" some common points into a parent interface invalidates Retrofit, but I don't have much experience with it so maybe I'm missing something here.

But just to be clear - I didn't have to struggle to fit my use case into Retrofit. It all came very natural, from the beginning when I just needed to get my data "javized" to now where I'm functional-testing many of my webservices and using these tests to generate their documentation using concordion. My goal is to make the steps for adding new tests as defined as possible - but not defined by some guidelines nobody will read, but by the code itself.

I can't say I've tried many solutions, though - If you honestly think I should walk away from Retrofit I'll do so (would love to hear about alternatives if that's end up being the case).

deigote commented 10 years ago

@JakeWharton needless to say that I'm more than willing to PR update myself if finally you guys decide to consider my request :)

eliasbagley commented 10 years ago

@JakeWharton I have a use for this also: I have a several interfaces which all share the same getEntity method:

public interface ContactsAPI { @GET(/company/contacts/{entity_id}) public void getEntity(@Path("company_id") Integer companyId, @Path("entity_id") Integer entityId, Callback callback); }

public interface AccountsAPI { @GET(/company/accounts/{entity_id}) public void getEntity(@Path("company_id") Integer companyId, @Path("entity_id") Integer entityId, Callback callback); }

public interface UserAPI { @GET(/company/users/{entity_id}) public void getEntity(@Path("company_id") Integer companyId, @Path("entity_id") Integer entityId, Callback callback); }

I want to do something like:

public interface entityAPI { @GET(/company/{feature}/{entity_id}) public void getEntity(@Path("company_id") Integer companyId, @Path("feature") String featureName, Callback callback); }

restAdapter.create(ContactAPI.class)

public interface contactAPI extends EntityAPI { }

restAdapter.create(ContactAPI.class)

Seems like a shame to have to duplicate so much when a lot of it is shared.

eyolas commented 10 years ago

same problem than eliasbagley.

Can you add a second parameter on create method to bypass test of interfaces ?

briantoth commented 10 years ago

I want to add my 2 cents here as well. Slightly different use case, but I want to split up my API into logical chunks (each of these chunks is implemented by a controller on the server). It would be awesome if I could have a single client API that just shoves all of these back together. Mostly an aesthetic thing, but it would be nice.

JakeWharton commented 10 years ago

Interfaces can only extend from a single other interface so that wouldn't work.

briantoth commented 10 years ago

I believe it is permissible in java for an interface to extend multiple interfaces (https://stackoverflow.com/questions/19546357/can-an-interface-extend-multiple-interfaces-in-java).

dasfuu commented 10 years ago

I am looking for the same thing as briantoth.

ransombriggs commented 10 years ago

I came across this change while doing an upgrade recently. I was using an interface to keep things consistent across multiple APIs, ie: my search endpoints should all look a certain way, and my crud endpoints should look a certain way. It also simplified my test cases, because I could in one test that all my search endpoints accept / require certain params, and for all crud cases I could verify not found behavior for GETs, etc. in one assertion. In the end, I ended up rewriting the tests methods using reflection, just thought I would add my two cents.

greeno commented 9 years ago

Quick patch to add support to disable this "feature" https://github.com/square/retrofit/pull/676 and https://github.com/greeno/retrofit

mohamedkomalo commented 8 years ago

since the PR #676 was closed, is there hope in that this will be enabled again, at least configurable ? I think this is a subjective opinion enforced while it should be optional, just because you guys think the best way to use retrofit is composition doesn't mean to make it the only way.

jaumard commented 8 years ago

Shame that PR #676 is closed :( I need this feature too...

edudar commented 8 years ago

What if we talk not about inheritance vs composition but same interface with different call adapters? With client convenience in mind, I want to provide a factory that can create blocking, async (java8) and reactive (rx) services. Method definitions between them are exactly the same except return values. So at the moment this results into 3 close to being identical interfaces. Would be much better to have parametrized common interface and several extensions per return type: T, CompletableFuture<T> and Observable<T>, for example?

JakeWharton commented 7 years ago

That requires runtime resolution of type parameters which I'm not really eager to get into the business of doing. Can you generate the interfaces from another specification like Swagger or even perhaps use an annotation processor?

On Wed, Nov 2, 2016 at 1:35 AM Eduard Dudar notifications@github.com wrote:

What if we talk not about inheritance vs composition but same interface with different call adapters? With client convenience in mind, I want to provide a factory that can create blocking, async (java8) and reactive (rx) services. Method definitions between them are exactly the same except return values. So at the moment this results into 3 close to being identical interfaces. Would be much better to have parametrized common interface and several extensions per return type: T, CompletableFuture and Observable, for example?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/504#issuecomment-257776905, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEYeWlfI3_lwgP7nZCIPJ1APhmpvmks5q6CEEgaJpZM4B-pOy .

edudar commented 7 years ago

Understood. Swagger would not be my weapon of choice for sure but custom annotation processor might be the way to go.

msimw commented 7 years ago

@deigote 你可以直接修改源码在本地使用, 第一步: public T create(final Class service) { if (!service.isInterface()) { throw new IllegalArgumentException("API declarations must be interfaces."); } if (validateEagerly) { eagerlyValidateMethods(service); }

第二步:private void eagerlyValidateMethods(Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getMethods()) { if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); } } }

第三步:@HttpApi("http://www.baidu.com/") public interface IBaiduPushHttpService extends IPushHttpService{ }

第四步:@Autowired private IPushHttpService pushHttpService;

@Test public void oneTest() throws IOException { this.pushHttpService.push().execute(); }

msimw commented 7 years ago

或者Object bean = retrofit.create(serviceClass);,这个serviceClass直接是顶级接口,子接口只是作为模板。

msimw commented 7 years ago

最好的解决办法就是作者,将类的访问控制符号设置为public,然后我们就可以自己扩展一些其他的功能了。(The best solution is the author, which sets the class's access control symbol to public, and then we can extend some of our other functions ourselves.)My English is poor。

co5dt commented 7 years ago

Hi there. Great lib, wouldn't know how to live on without it. Solves all usecases in my apps, but one is still unmet. Just pointing this out so I don't get asked why I even use retrofit. :)

But issue remains: #504 !

This is needed, really. Example: `TokenHandler jwtHandler = new JWTTokenHandler(context); Api api = ApiFactory(jwtHandler).createService(clazz);

Observable
        .from(entities)
        .flatMap(api::save)
        .doOnNext(entity -> entity.setSynced(true))
        .toList()
        .doOnNext(/*save to db, etc*/)
        .subscribe(entities -> {}, Throwable::printStackTrace);`

Here and there I read JW favors composition over inheritance and that's why we must write this 13 times, given we have 13 endpoints for 13 entities in 13 service interfaces.

Now I could have a single interface for post requests with 13 methods, each one for a different entity.

` public interface UploadApi {

@POST("users") Observable save(User user);

@POST("user-groups") Observable save(UserGroup userGroup);

@POST("user-photos") Observable save(UserPhoto userPhoto);

@POST("user-text-notes") Observable save(UserTextNote userTextNote);

@POST("user-actions") Observable save(UserAction userAction);

@POST("user-activities") Observable save(UserActivity userActivity);

@POST("pois") Observable save(Poi poi);

@POST("poi-collections") Observable save(PoiCollection poi);

// and so on ... } ` I have seen some projects by now and all of them specify their service interfaces around entites (or dto's or whatya wanna call 'em) like so:

`public interface UserApi {

@GET("users") Observable<List> get();

@GET("users/{id}") Observable get(@Path("id") long id);

@GET("users/{login}") Observable get(@Path("login") String login);

@POST("users") Observable save(User user);

@POST("users") Observable save(List user);

@DELETE("users") Observable delete(List user);

@DELETE("users/{id}") Observable delete(@Path("id") long user);

@GET("account") Observable getCurrentUser(); }`

I have read somewhere that a library should not be in the way of things but help you to do something more easily. Please reconsider.

Anyway, all the best and thanks for this great lib.

gavinromberger commented 6 years ago

Feature Request

I would like to create a base api service which can be implemented in terms of generics. http://b.android.com/58753 has been resolved and while I understand that composition is the preferred pattern, inheritance can be a very powerful one. Inheritance can help with utilizing large scale consistent apis. I have a rest api with about a hundred endpoints that all expose POST, PATCH, GET and DELETE. As it stands I have two options. 1 - create one massive service api and copy the same blocks of annotated code hundreds of times. 2 - create about a hundred service apis and still copy the same blocks of annotated code hundreds of times. This begs for inheritance. The following code is an example of the inheritance pattern I and others from what I can tell would love to see. This has been an ongoing feature request pattern for about 4 years now.

Note: I have omitted all the @Path, @Header, @HeaderMap, @QueryMap and other annotations that my use case necessitates in order to be concise.

interface BaseService<Response, PostBody> {
    @POST("end-point")
    fun post(
        @Body body : PostBody
    ) : Call<Response>
}

interface SubService : BaseService<SubResponse, SubPostBody> {
    companion object {
        fun create(): SubService {
             val retrofit: Retrofit =  Retrofit.Builder()
                .addConverterFactory(MoshiConverterFactory.create())
                .baseUrl(SOME_URL)
                .build()
            return retrofit.create(SubService::class.java)
        }
    }
}
co5dt commented 6 years ago

This has been an ongoing feature request pattern for about 4 years now.

Give it up, move on, copy-Paste it 1000 times and suffer in silence.

naturalwarren commented 6 years ago

FWIW I wanted to do this today to make migrating some legacy code from Retrofit 1 to Retrofit 2 easier.

gavinromberger commented 6 years ago

@co5dt I gave up, I moved on, I copy and pasted it 1000 times and the suffering continues...

felislynx-silae commented 6 years ago

To be honest, i think this is very nice feature. If you build application with multiple flavors it is very common to have structure like: main -> BaseUserInterface client1 -> UserInterface extends BaseUserInterface (adds some new calls) client2 -> UserInterface extends BaseUserInterface (adds another set of new calls) client3 -> UserInterface extends BaseUserInterface (doesn't add any new calls)

This is very clean approach. And not being able to extend interface require lots of work where code is much less readable to achieve same behaviour

JakeWharton commented 6 years ago

Why wouldn't you just split those up into multiple interfaces? Clearly they have semantic meaning based on the variant so codify that meaning into the type system.

On Tue, Apr 24, 2018 at 10:47 AM Bartosz Wyspiański < notifications@github.com> wrote:

To be honest, i think this is very nice feature. If you build application with multiple flavors it is very common to have structure like: main -> BaseUserInterface client1 -> UserInterface extends BaseUserInterface (adds some new calls) client2 -> UserInterface extends BaseUserInterface (adds another set of new calls) client3 -> UserInterface extends BaseUserInterface (doesn't add any new calls)

This is very clean approach. And not being able to extend interface require lots of work where code is much less readable to achieve same behaviour

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/504#issuecomment-383960084, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEatmTNeiQkwKbJmPz5--v5gDu1Gnks5trzrtgaJpZM4B-pOy .

gavinromberger commented 6 years ago

My problem is that I must split them up into multiple interfaces that cannot take advantage of basic principles of inheritance or generics. Each of my ApiServices is generally the same, but they need to be different in three ways that could be solved by inheritance and generics. 1) The string required by each APiService's @POST, @PATCH, @GET annotation is different. Solved by abstraction and inheritance. 2) The object type required by the @Body annotation needs to be type safe and different for each ApiService. Solved by generics. 3) The Call return type of ApiService method needs to also be type safe and different for each. Again solved by generics.

If I had one Api service, implemented in terms of generics, and open to inheritance then each one of my plethora of ApiServices could go from 100 lines of code to 15 lines of code, needing only to specify its api endpoint through abstraction, and its Body and Call object type through generics. It could pivot from a twisted ugly maintenance issue to a beautifully crafted example of pattern recognition, abstraction and inheritance implemented through generics.

minaasamaan commented 6 years ago

That's really upsetting, I liked retrofit a lot but now I just cannot understand why disagreeing with everyone just for the sake of disagreement! I've implemented a generic proxy pipeline for CRUD operations in downstream dependencies, and provided a generic retrofit interface which will be extended by potential proxied service clients, and while doing integration test, I found this non-sense error! Now, for each new (to be proxied) downstream dependency that we want to integrate with our backend API layer, we have to duplicate exact same code just because inheritance/polymorphism is not allowed!!
So either copy/paste logic/tests, or search for different lib & do the same infrastructure we did built on top of retrofit again. I really hope that you guys reconsider hearing all of these voices!

devindi commented 6 years ago

Hi all!

I faced with the case in which interface inheritance will be useful. I have a library with interface like that:

interface AuthService {
    void authorize(String login, String password);
}

And 2 apps uses this lib: app1:

interface App1AuthService extends AuthService {
    @GET("/auth")
    @Override
    void authorize(@Query("login") String login, @Query("password") String password);
}

app2:

interface App2AuthService extends AuthService {
    @GET("/auth/special")
    @Override
    void authorize(@Query("login") String login, @Query("password") String password);
}

So now I would like to inject correct implementation of AuthService into lib but I can't due to retrofit restriction =(

co5dt commented 6 years ago

It's been almost a year now since I follow this thread and every time I get an update, I just shake my head a little.

Let's fork this awesome library to overcome the authors s....y attitude.

First thing I'll do once I'm back from vacation.

swankjesse commented 6 years ago

Retrofit tries to make REST APIs simple. We do our best to make APIs that are easy to call, configure, and test.

We have made several decisions in Retrofit where we’ve deliberately left something out in order to focus and simplify the library. Some of these decisions may seem obvious, but often they required a lot of research.

Just because we disagree on this particular issue does not mean we’re shitty or lazy. Suggesting so is discouraging.

JakeWharton commented 6 years ago

Also there's that whole thing where it is broken on certain versions of Android…

darwind commented 6 years ago

@JakeWharton you mention that there are versions of Android where this wouldn't work. Could you specify which versions of Android that it doesn't work on? I came across this issue just recently, because I'm working on a whitelabel solution of an app where we use different flavours and different flavours sometimes mean different endpoints, but most endpoints are the same, so for me inheritance is the obvious solution for this.

Consider this:

I have flavour A that uses endpoint:

interface Api {
    String BASE_URL = "http://myurl.com/";

    @GET("{link}")
    LiveData<Data> getItem(@Path(value = "link", encoded = true) String link);

    @GET("{link}")
    LiveData<Response> getItems(@Path(value = "link", encoded = true) String link);
}

Now I also have flavour B, that uses the same API, except that it also has an extra method:

    @GET("{link}")
    LiveData<Response> getItems(@Path(value = "link", encoded = true) String link);

Now for brevity and for the sake of the next developer and also for the sake of not duplicating code, I would really love to be able to have a BaseApi interface that I could just inherit from, but obviously I can't because Retrofit doesn't allow it.

I get that you guys favor composition over inheritance and I completely agree that you should use composition as much as possible, but there is a reason why Java still supports inheritance as well as composition.

Retrofit is such an integrated part of Android these days and I'm even surprised why it hasn't been moved into Jetpack or something similar, but maybe Google is thinking of making this move at some point in the near future (would be nice 🙂). While you guys obviously has the final say in this matter I really hope you could reconsider opening up for this - isn't it pretty clear that the community wants this? 🙂

I'll keep copy-pasting code around for now, but it would be amazing to have this sorted at some point.

If the final say has been said in this matter then you should close this issue so we can all move on.

jaxley commented 5 years ago

This is a super-frustrating restriction. And it was fun to find out at runtime!

I have a similar use case as @devindi where I need to choose the right API implementation dynamically for AWS ECS metadata because they are the same except for the URLs.

    String ecsV3Uri = System.getenv("ECS_CONTAINER_METADATA_URI");

    Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
        .addConverterFactory(JacksonConverterFactory.create(mapper))
        .client(httpClient);

    if (StringUtils.isEmpty(ecsV3Uri)) {
      // this is a v2 API (AWS Fargate ECS)
      retrofitBuilder
          .baseUrl("http://169.254.170.2/v2/");
      return retrofitBuilder.build().create(Ecsv2MetadataApi.class);
    }
    else {
      // this is a v3 API (EC2-based ECS)
      retrofitBuilder
          .baseUrl(ecsV3Uri + '/');
      return retrofitBuilder.build().create(Ecsv3MetadataApi.class);
    }
JakeWharton commented 5 years ago

It's likely that 2.7.0 will remove the restriction by removing support for Android versions where proxying an interface with a supertype does not work (which is the source of the current limitation).

On Wed, Jun 5, 2019 at 11:54 AM Jason Axley notifications@github.com wrote:

This is a super-frustrating restriction. And it was fun to find out at runtime!

I have a similar use case as @devindi https://github.com/devindi where I need to choose the right API implementation dynamically for AWS ECS metadata because they are the same except for the URLs.

String ecsV3Uri = System.getenv("ECS_CONTAINER_METADATA_URI");

Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
    .addConverterFactory(JacksonConverterFactory.create(mapper))
    .client(httpClient);

if (StringUtils.isEmpty(ecsV3Uri)) {
  // this is a v2 API (AWS Fargate ECS)
  retrofitBuilder
      .baseUrl("http://169.254.170.2/v2/");
  return retrofitBuilder.build().create(Ecsv2MetadataApi.class);
}
else {
  // this is a v3 API (EC2-based ECS)
  retrofitBuilder
      .baseUrl(ecsV3Uri + '/');
  return retrofitBuilder.build().create(Ecsv3MetadataApi.class);
}

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/504?email_source=notifications&email_token=AAAQIEO775TJY47UKKKOH53PY7OTRA5CNFSM4AP2SOZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXAFKFY#issuecomment-499143959, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAQIEL3DWPKIB33SNKNO7DPY7OTRANCNFSM4AP2SOZA .

joe-striedl commented 5 years ago

That would be amazing. would it be possible to re-open https://github.com/square/retrofit/pull/676 to enable this feature as an option in the near future? I just stumbled upon this same issue in our project and was a bit jarred by the failure at runtime.

shiSHARK commented 5 years ago

This issue is still present in the released 2.6.1 and 2.6.2 versions of retrofit. Somehow it appears that the commit was not included in the release.

JakeWharton commented 5 years ago

That's correct. Those releases were made from the 2.6.0 branch.

On Thu, Oct 31, 2019, 1:34 PM shiSHARK notifications@github.com wrote:

This issue is still present in the released 2.6.1 and 2.6.2 versions of retrofit. Somehow it appears that the commit was not included in the release.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/504?email_source=notifications&email_token=AAAQIEOJGUV2XIT2RRWO6QLQRMJJFA5CNFSM4AP2SOZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECYT5QY#issuecomment-548486851, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQIEND2LI7XBJ67P2SI2LQRMJJFANCNFSM4AP2SOZA .

hkawii commented 4 years ago

That's correct. Those releases were made from the 2.6.0 branch. On Thu, Oct 31, 2019, 1:34 PM shiSHARK @.***> wrote: This issue is still present in the released 2.6.1 and 2.6.2 versions of retrofit. Somehow it appears that the commit was not included in the release. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#504?email_source=notifications&email_token=AAAQIEOJGUV2XIT2RRWO6QLQRMJJFA5CNFSM4AP2SOZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECYT5QY#issuecomment-548486851>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQIEND2LI7XBJ67P2SI2LQRMJJFANCNFSM4AP2SOZA .

So how can we get that feature ? on which version ?

JakeWharton commented 4 years ago

It is not released

On Thu, Nov 21, 2019 at 9:48 AM HebaMohamed notifications@github.com wrote:

That's correct. Those releases were made from the 2.6.0 branch. … <#m5575032184380938997> On Thu, Oct 31, 2019, 1:34 PM shiSHARK @.***> wrote: This issue is still present in the released 2.6.1 and 2.6.2 versions of retrofit. Somehow it appears that the commit was not included in the release. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#504 https://github.com/square/retrofit/issues/504?email_source=notifications&email_token=AAAQIEOJGUV2XIT2RRWO6QLQRMJJFA5CNFSM4AP2SOZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECYT5QY#issuecomment-548486851>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQIEND2LI7XBJ67P2SI2LQRMJJFANCNFSM4AP2SOZA .

So how can we get that feature ? on which version ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/504?email_source=notifications&email_token=AAAQIEOVR3E4VORDTEFEOZLQU2NVXA5CNFSM4AP2SOZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEE2PDKA#issuecomment-557117864, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQIEKHCNM73HXXC7BKF4LQU2NVXANCNFSM4AP2SOZA .

jalotra commented 4 months ago

Afaik now in 2.9.0 in 2024, this limitation is no more there ? @JakeWharton