restricciones programming programaciĆ³n programacion multiparadigma globales constraint con java generics retrofit retrofit2

java - programming - Los tipos inferidos de tipos incompatibles no se ajustan a las restricciones de igualdad



programaciĆ³n con restricciones (1)

Así que tengo un modelo de Model .

public class Model { .... }

Esto tiene dos subclases:

public class SubmodelA extend Model { .... }

y

public class SubmodelB extend Model { .... }

Estos tres están envueltos en la clase de Data .

public class ApiData<T extends Model> { public T data; }

Mi response wrapper general se ve así:

public class ApiResponse<DATA> { DATA data; }

La operación api "ficticia" sigue siendo la misma:

public interface Endpoints { Call<ApiResponse<ApiData>> getData(); }

Tengo una implementación de retrofit2.Callback para manejar las respuestas:

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); } }

El 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)); } }

El compilador golpea ApiCallbackProxy.with(callback) con este error:

Así que quiero, dependiendo de dónde se utiliza esta llamada a la API en la aplicación para devolver una subclase de modelo diferente o el modelo en sí.

es decir.

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) -> {};


La clase ApiClient tiene un oyente que espera que ApiData<U> en la respuesta.

El problema es que no hay U Tiene un Endpoint , y el punto final no tiene tipos genéricos, y devuelve solo ApiData sin ningún tipo concreto seleccionado para el genérico.

Este es un caso de genéricos que han salido mal. La idea habitual sería hacer que Endpoint sea genérico:

public interface Endpoints<U> { Call<ApiResponse<ApiData<U>>> getData(); }

Sin embargo, ¿qué hace el Retrofit ? Convierte la API HTTP en la interfaz de Java. Y observando el ejemplo más simple en el repositorio github de Retrofit , me parece bastante claro que se supone que debe colocar interfaces que accedan a algún punto final HTTP real. No es un GET abstracto.

Así que prefieres darle un tipo concreto a que sea genérico. Hacer algo como:

public interface Endpoints { Call<ApiResponse<ApiData<Model>>> getData(); }

Espero que Retrofit deserialice los datos en la respuesta a su Model . Por lo tanto, tener una clase concreta en lugar de una variable de tipo genérico no configurada es crucial para la deserialización exitosa. Sin embargo, solo puede usarlo con escuchas que sean cualquiera de los siguientes:

ApiResultListener<ApiResponse<Data<Model>>> ApiResultListener<ApiResponse<Data<? super Model>>>

Además, en la parte anterior de la pregunta, la ApiResponse<Payload> donde la variable de tipo genérico se ve como si fuera una clase de Payload , ahora es bastante tortuosa :)