Несовместимые типы, выведенные типа, не соответствуют ограничениям (ограничениям)
Итак, у меня есть модель Model
.
public class Model { .... }
У этого есть два подкласса:
public class SubmodelA extend Model { .... }
и
public class SubmodelB extend Model { .... }
Эти три заключены в класс Data
.
public class ApiData<T extends Model> {
public T data;
}
Мой общий response wrapper
выглядит следующим образом:
public class ApiResponse<DATA> {
DATA data;
}
Операция "dummy" api остается той же:
public interface Endpoints {
Call<ApiResponse<ApiData>> getData();
}
У меня есть реализация retrofit2.Callback
для обработки ответов:
public class ApiCallbackProxy<T> implements retrofit2.Callback<T> {
public interface ApiResultListener<RESPONSE_TYPE> {
void onResult(RESPONSE_TYPE response, ApiError error);
}
private ApiResultListener<T> mListener;
private ApiCallbackProxy(ApiResultListener<T> listener) {
mListener = listener;
}
@Override
public void onResponse(Call<T> call, Response<T> response) {
}
@Override
public void onFailure(Call<T> call, Throwable t) {
}
public static <T> ApiCallbackProxy<T> with(ApiResultListener<T> callback) {
return new ApiCallbackProxy<>(callback);
}
}
ApiClient
public class ApiClient {
public Endpoints mRetrofit;
public ApiClient() {
Retrofit retrofit = new Retrofit.Builder().build();
mRetrofit = retrofit.create(Endpoints.class);
}
public <U extends Model> void getData(ApiResultListener<ApiResponse<ApiData<U>>> callback) {
//Compiler hits here
mRetrofit.getData().enqueue(ApiCallbackProxy.with(callback));
}
}
Компилятор попадает в ApiCallbackProxy.with(callback)
с этой ошибкой:
![введите описание изображения здесь]()
Итак, я хочу, в зависимости от того, где этот API-вызов используется в приложении, чтобы вернуть другой подкласс модели или самой модели.
т.
public static void main (String[] args) {
ApiClient apiClient = new ApiClient();
apiClient.getData(listener2);
}
public static final ApiResultListener<ApiResponse<Data<SubmodelA>>> listener = (response, error) -> {};
public static final ApiResultListener<ApiResponse<Data<Model>>> listener2 = (response, error) -> {};
public static final ApiResultListener<ApiResponse<Data<SubmodelB>>> listener3 = (response, error) -> {};
Ответы
Ответ 1
В классе ApiClient
есть слушатель, ожидающий ApiData<U>
в ответе.
Проблема в том, что нет U
. У вас есть Endpoint
, а конечная точка не имеет общих типов и возвращает только ApiData
без конкретного типа, выбранного для общего.
Это случай, когда дженерики пошли не так. Обычная идея состояла бы в том, чтобы сделать конечную точку общей:
public interface Endpoints<U> {
Call<ApiResponse<ApiData<U>>> getData();
}
Однако, что делает Retrofit
? Он превращает HTTP API в интерфейс Java. И, глядя на самый простой пример в github repo of Retrofit, мне кажется довольно понятным, что вы должны поместить интерфейсы, которые обращаются к некоторым реальной конечной точки HTTP. Это не абстрактное GET
.
Итак, вам лучше дать конкретный тип, чем сделать его общим. Сделайте что-то вроде:
public interface Endpoints {
Call<ApiResponse<ApiData<Model>>> getData();
}
Я ожидаю, что Retrofit будет десериализовать данные в ответе на ваш Model
. Таким образом, для успешного десериализации важно иметь конкретный класс, а не неопределенную типичную переменную типа. Тем не менее, вы можете использовать его только с прослушивателями:
ApiResultListener<ApiResponse<Data<Model>>>
ApiResultListener<ApiResponse<Data<? super Model>>>
Кроме того, в старшей части вопроса ApiResponse<Payload>
, где переменная типа generic выглядит как класс Payload
, теперь это довольно коварно:)