Я использую Retrofit2 и RxJava2CallAdapterFactory
.
API, который я использую, всегда возвращает код состояния, равный 200, и для строки JSON успеха и ответа структура JSON совершенно иная. Поскольку код состояния всегда равен 200, метод onResponse() вызывается всегда. Следовательно, я не могу извлечь сообщения об ошибках из JSON в состоянии ошибки.
Решение 1:
Я использую ScalarsConverterFactory
для получения строки ответа и вручную использую Gson для анализа ответа. Как получить ответ в виде строки с помощью модернизации без использования GSON или любой другой библиотеки в Android
Проблема с этим решением: я планирую использовать RxJava2CallAdapterFactory, чтобы метод модернизации возвращал класс DataModel.
Мне нужно найти лучшее решение для этой проблемы, так как я могу продолжать возвращать классы модели данных из метода Retrofit и каким-то образом определить условие ошибки по ответу (определить, что JSON ответа не соответствует модели данных), а затем проанализировать ошибку JSON в модель данных.
Модернизированный клиент
public static Retrofit getClient(String url) {
if (apiClient == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(interceptor).build();
apiClient = new Retrofit.Builder()
.baseUrl(url)
/*addCallAdapterFactory for RX Recyclerviews*/
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
/* add ScalarsConverterFactory to get json string as response */
// .addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
// .addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient)
.build();
}
return apiClient;
}
метод
public static void getLoginAPIResponse(String username, String password, String sourceId, String uuid, final HttpCallback httpCallback) {
baseUrl = AppPreference.getParam(UiUtils.getContext(), SPConstants.BASE_URL, "").toString();
ApiInterface apiService =
ApiClient.getClient(baseUrl).create(ApiInterface.class);
Call<LoginBean> call = apiService.getLoginResponse(queryParams);
call.enqueue(new Callback<LoginBean>() {
@Override
public void onResponse(Call<LoginBean> call, Response<LoginBean> response) {
if (response.body().isObjectNull()) {
httpCallback.resultCallback(APIConstants.API_LOGIN, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_FAILURE, 0, null);
return;
}
httpCallback.resultCallback(APIConstants.API_LOGIN, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_SUCCESS, response.code(), response.body());
}
@Override
public void onFailure(Call<LoginBean> call, Throwable t) {
// Log error here since request failed
httpCallback.resultCallback(APIConstants.API_APP_VERIFICATION, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_FAILURE, 0, t);
t.printStackTrace();
}
});
}
Интерфейс
@GET("App/login")
Call<LoginBean> getLoginResponse(@QueryMap Map<String, String> queryMap);
PS: API пока не может измениться, так как некоторые другие приложения его потребляют.
-
Парсер Gson не возвращает экземпляр нулевого объекта, чтобы я понял, что существует несоответствие структуры json и модели данных.
-
RestAdapter устарел в Retrofit 2
Я ищу лучший подход для решения этой проблемы, желательно избегать анализа json вручную и максимально использовать адаптеры RX для модернизации и модернизации.
РЕДАКТИРОВАТЬ
Код ответа 200 отсюда
-
response.isSuccessful() == true
-
response.body() != null
также имеет значение true, поскольку Gson никогда не создает пустой экземпляр или выдает какое-либо исключение, если имеется несоответствие структуры JSON -
response.errorBody() == null
всегда, когда ответ отправляется как поток ввода с сервера.if (response.isSuccessful() && response.body() != null) { //control always here as status code 200 for error condition also }else if(response.errorBody()!=null){ //control never reaches here }
РЕДАКТИРОВАТЬ 2
РЕШЕНИЕ
Решение основано на ответе на вопрос
- Я создал базовый родительский класс для дальнейшего ответа.
- Так как у меня есть несколько моделей API и данных, я должен создать для каждого
BASE API BEAN
public class BaseApiBean<T> {
@Nullable
private T responseBean;
@Nullable
private ErrorBean errorBean;
public BaseApiBean(T responseBean, ErrorBean errorBean) {
this.responseBean = responseBean;
this.errorBean = errorBean;
}
public T getResponseBean() {
return responseBean;
}
public void setResponseBean(T responseBean) {
this.responseBean = responseBean;
}
public ErrorBean getErrorBean() {
return errorBean;
}
public void setErrorBean(ErrorBean errorBean) {
this.errorBean = errorBean;
}
}
БАЗОВЫЙ ДЕЗЕРИАЛИЗАТОР
public abstract class BaseDeserializer implements JsonDeserializer<BaseApiBean> {
@Override
public BaseApiBean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
// Get JsonObject
final JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("result")) {
/* {"result":"404"}*/
ErrorBean errorMessage = new Gson().fromJson(jsonObject, ErrorBean.class);
return getResponseBean(errorMessage);
} else {
return getResponseBean(jsonObject);
}
}
public abstract BaseApiBean getResponseBean(ErrorBean errorBean);
public abstract BaseApiBean getResponseBean(JsonObject jsonObject);
}
Настраиваемый десериализатор для каждого API
public class LoginDeserializer extends BaseDeserializer {
@Override
public BaseApiBean getResponseBean(ErrorBean errorBean) {
return new LoginResponse(null, errorBean);
}
@Override
public BaseApiBean getResponseBean(JsonObject jsonObject) {
LoginBean loginBean = (new Gson().fromJson(jsonObject, LoginBean.class));
return new LoginResponse(loginBean, null);
}
}
ТАМОЖЕННЫЙ ОТВЕТНЫЙ БИН
public class LoginResponse extends BaseApiBean<LoginBean> {
public LoginResponse(LoginBean responseBean, ErrorBean errorBean) {
super(responseBean, errorBean);
}
}
КЛИЕНТ
public class ApiClient {
private static Retrofit apiClient = null;
private static Retrofit apiClientForFeedBack = null;
private static LoginDeserializer loginDeserializer = new LoginDeserializer();
private static AppVerificationDeserializer appVerificationDeserializer = new AppVerificationDeserializer();
public static Retrofit getClient(String url) {
if (apiClient == null) {
GsonBuilder gsonBuilder=new GsonBuilder();
gsonBuilder.registerTypeAdapter(LoginResponse.class,
loginDeserializer);
gsonBuilder.registerTypeAdapter(AppVerificationResponse.class,
appVerificationDeserializer);
Gson gson= gsonBuilder.create();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.connectTimeout(15, TimeUnit.SECONDS)
.build();
apiClient = new Retrofit.Builder()
.baseUrl(url)
/*addCallAdapterFactory for RX Recyclerviews*/
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
/* add ScalarsConverterFactory to get json string as response */
// .addConverterFactory(ScalarsConverterFactory.create())
// .addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient)
.build();
}
return apiClient;
}
РУЧНОЙ ОТВЕТ
public static void getLoginAPIResponse(String username, String password, String sourceId, String uuid, final HttpCallback httpCallback) {
baseUrl = AppPreference.getParam(getContext(), SPConstants.MT4_BASE_URL, "").toString();
ApiInterface apiService =
ApiClient.getClient(baseUrl).create(ApiInterface.class);
HashMap<String, String> queryParams = new HashMap<>();
queryParams.put(APIConstants.KEY_EMAIL, sourceId + username.toLowerCase());
queryParams.put(APIConstants.KEY_PASSWORD, Utils.encodePwd(password));
Call<LoginResponse> call = apiService.getLoginResponse(queryParams);
call.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.body().getResponseBean()==null) {
httpCallback.resultCallback(APIConstants.API_LOGIN, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_FAILURE, 0, response.body().getErrorBean());
return;
}
httpCallback.resultCallback(APIConstants.API_LOGIN, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_SUCCESS, response.code(), response.body().getResponseBean());
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
// Log error here since request failed
httpCallback.resultCallback(APIConstants.API_APP_VERIFICATION, HttpCallback.REQUEST_TYPE_GET,
HttpCallback.RETURN_TYPE_FAILURE, 0, t);
t.printStackTrace();
}
});
}