5

Hi I am working with java 8. Below is the case:

I have an empty interface AsyncResponse like below:

package com.personal.carrot.core.models;

public interface AsyncResponse {
}

And I have a model APIResponse

package com.personal.carrot.core.models;

import org.codehaus.jackson.annotate.JsonProperty;

public class APIResponse implements AsyncResponse {

    @JsonProperty("numberOfFeatures")
    public Long numberOfFeatures;

}

And finally I have a service using Retrofit2 to make my API response:

public interface APIRepository {
    @POST("MYURL")
    Call<APIResponse> resolveCounts(@Body HashMap<String, String> body);
}

Now when I call the APIRepository like below:

Call<AsyncResponse> request = repository.resolveCounts(payload);

I get an error:

java: incompatible types: retrofit2.Call (com.personal.carrot.core.models.APIResponse) cannot be converted to retrofit2.Call(com.personal.carrot.core.models.AsyncResponse)

iam.Carrot
  • 4,976
  • 2
  • 24
  • 71
  • 1
    @ernest_k No there is a single instance JVM & this is a compile time error. – iam.Carrot Jan 24 '19 at 06:03
  • Does it work if you use `Call extends AsyncResponse>`? – Hulk Jan 24 '19 at 06:25
  • See [the oracle generics tutorial](https://docs.oracle.com/javase/tutorial/java/generics/inheritance.html): "Box and Box are not subtypes of Box" - if `resolveCounts` returns an `Call`, you cannot assign that to an `Call`. – Hulk Jan 24 '19 at 06:35
  • See also: https://stackoverflow.com/questions/2501023/demonstrate-covariance-and-contravariance-in-java – Hulk Jan 24 '19 at 06:41

2 Answers2

1

It's failing because you cannot assign a Call<APIResponse> to a Call<AsyncResponse>. Generic types are invariant.

You probably have to use APIResponse as type argument for your variable:

Call<APIResponse> request = repository.resolveCounts(payload);

That is not because you can't design your code to use the interface AsyncResponse, but because (I'm presuming here) the framework uses the return type to process content-type-related bindings.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
0

Why It Doesn't Work

Contrary to the common understanding about polymorphism (which is what you are trying to accomplish here), it doesn't apply to generics.

List<String> strList = new ArrayList();
List<Object> objectList = strList;

The above example will produce a compilation error.

This is because IF we allow the second line to succeed, there may be a situation where subsequently objectList gets assigned a list of another type (e.g. List<Integer>). strList will now be 'corrupted' because objectList holds the same reference as strList.

As such, we need to return the exact same type as what that list is explicitly declaring to hold, and not either a sub-class or super-class of AsyncResponse.

Potential Solutions

Depending on what you are trying to achieve here, a potential solution would be:

Call<APIResponse> request = repository.resolveCounts(payload);

or (and I haven't tried this yet):

Call<? extends ASyncResponse> request = repository.resolveCounts(payload);
Timothy T.
  • 1,031
  • 1
  • 12
  • 25