Как мы можем обрабатывать разные типы ответов с помощью Retrofit 2?
У меня есть webservice, который возвращает либо список сериализованных объектов MyPOJO:
[
{ //JSON MyPOJO },
{ //JSON MyPOJO }
]
либо объект ошибки:
{
'error': 'foo',
'message':'bar'
}
Используя функцию retrofit2, как я могу получить ошибку?
Call<List<MyPOJO>> request = ...
request.enqueue(new Callback<List<MyPOJO>>() {
@Override
public void onResponse(Response<List<MyPOJO>> response) {
if (response.isSuccess()) {
List<MyPOJO> myList = response.body();
// do something with the list...
} else {
// server responded with an error, here is how we are supposed to retrieve it
ErrorResponse error = ErrorResponse.fromResponseBody(apiService.getRetrofitInstance(), response.errorBody());
processError(error);
// but we never get there because GSON deserialization throws an error !
}
}
@Override
public void onFailure(Throwable t) {
if(t instanceof IOException){
// network error
}else if(t instanceof IllegalStateException){
// on server sending an error object we get there
// how can I retrieve the error object ?
}else {
// default error handling
}
}
}
Вот исключение GSON:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Экземпляр "Дооснащения" создается с использованием GsonConverterFactory
Ответы
Ответ 1
У меня была аналогичная проблема, и я решил ее, используя общий Object
, а затем проверил, какой тип ответа у меня был с помощью instanceof
Call<Object> call = api.login(username, password);
call.enqueue(new Callback<Object>()
{
@Override
public void onResponse(Response<Object> response, Retrofit retrofit)
{
if (response.body() instanceof MyPOJO )
{
MyPOJO myObj = (MyPOJO) response.body();
//handle MyPOJO
}
else //must be error object
{
MyError myError = (MyError) response.body();
//handle error object
}
}
@Override
public void onFailure(Throwable t)
{
///Handle failure
}
});
В моем случае у меня было либо MyPOJO, либо MyError, и я мог быть уверен, что это будет один из них.
В других случаях я имел backend возвратить тот же объект ответа независимо от того, был ли запрос успешным или нет.
Затем внутри этого объекта ответа у меня были фактические данные в поле "Объект". Затем я могу использовать экземпляр для определения того, какой тип данных у меня был. В этом случае я всегда возвращал один и тот же объект, независимо от того, какой вызов был.
public class MyResponse {
private int responseCode;
private String command;
private int errorno;
private String errorMessage;
private Object responseObject; //This object varies depending on what command was called
private Date responseTime;
}
Ответ 2
Call<LoginResponse> call = apiService.getUserLogin(usernametext, passwordtext);
call.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
Log.e("responsedata","dd"+response.toString());
if (response.code()==200) {
showMessage(response.body().getMessage());
Intent intent = new Intent(LoginActivity.this, MainAct.class);
startActivity(intent);
}
else
try {
LoginError loginError= gson.fromJson(response.errorBody().string(),LoginError.class);
showMessage(loginError.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}