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 :)