Вот мой пример JSON, когда пользователь успешно аутентифицируется
{
"status": "success",
"message": "",
"data": {
"_id": {
"$id": "..."
},
"email": "...",
"name": "...",
"mobile": "...",
"mobile_status": "...",
"email_status": "..."
}
}
И когда учетные данные пользователя неверны
{
"status": "error",
"message": {
"msg": [
"Login detail incorrect"
]
},
"data": ""
}
Обратите внимание на изменение типов данных message и data. Используя модификацию с этим, я получил известную ошибку Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $.
Чтобы решить эту проблему, я последовал примеру это, чтобы решить проблему. Что действительно решило проблему ОБЪЕКТА/МАССИВА.
У меня есть 3 модели LoginResponse, MessageResponse, DataResponse, и вот как я пытаюсь получить доступ к MessageResponse и DataResponse.
Я не уверен, что смогу использовать даже 2
Gson messageDeserializer = new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new MessageDeserializer()).create();
Gson dataDeserializer = new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new DataDeserializer()).create();
builder.addConverterFactory(GsonConverterFactory.create(messageDeserializer));
builder.addConverterFactory(GsonConverterFactory.create(dataDeserializer));
Я не думаю, что эти пользовательские JsonDeserializer работают так, как должны. Я не могу вернуть ответ от этих JsonDeserializer. Единственный способ, которым я могу получить к ним доступ только как строку, которая даже не является правильной строкой в формате JSON.
Также переключение обратного порядка .addConverterFactory иногда вызывает сбой при доступе к модели LoginResponse.
У вас есть доступ к кодам сетевых ошибок и ответов? Таким образом, вы можете создать оператор switch, который явно определяет, как вы будете десериализовать ЛЮБОЙ ответ.
Например,
Gson switchToDeserialise(int errorCode){
///i assume 200 means correct response. And 404 means there's an errorCode
Gson deserializer = new GsonBuilder().create();
switch(errorCode){
case 200:
return new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new DataDeserializer()).create();
case 404:
return new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new MessageDeserializer()).create();
default:
return deserializer;}}
Примечание. Приведенный выше код не тестировался.
=================================== НЕМНОГО АВАРИЙНОГО РЕДАКТИРОВАНИЯ ДЕЙСТВИТЕЛЬНО ========= ================================================== ==================
Основываясь на разговоре, который у нас был, и на моем наблюдении как за успехом, так и за ответом об ошибке, у меня есть этот непроверенный код/предложение:
//in the retrofit response callback, get the status via JSONObject
JSONObject status = new JSONObject(response.toString()); throws Exception
String statusString = status.optString("status");
//now take the result of the string to a switch statement
Gson switchToDeserialise(String statusString){
///from what you've shown in the success & failure responses, status is either success or error, so...
Gson deserializer = new GsonBuilder().create();
switch(statusString){
case "success":
return new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new DataDeserializer()).create();
case "error":
return new GsonBuilder().setLenient().registerTypeAdapter(LoginResponse.class, new MessageDeserializer()).create();
default:
return deserializer;
}
}
Хорошо я понял. Вот идея: после получения ответа используйте библиотеку JSONObject, чтобы запросить результат status, а затем сформулируйте оператор переключения, чтобы определить вашу десериализацию.
Плохо, я только что понял, что у меня есть другой код ответа 200 для успешного входа и 207 для неудачного входа. Но как мне передать Custom CoverterFactory внутри метода onResponse или есть способ определить код ответа до этого? На данный момент, на основе состояния успеха/ошибки, я вручную десериализую ответ, используя new Gson().fromJson(data, DataResponse.class);.
Также, когда не удалось войти в систему (POJO, который я создал онлайн), я получаю исключение nullPointerException при доступе к методу getMsg (после передачи JSON в десериализаторе)
Если вы используете retrofit, вы можете получить errorCode из кода ответа # и из методов onResponse и onError, чтобы вы могли поместить метод switchToDeserialise в оба обратных вызова. По отношению к NPE, который вы получаете от getMsg, должно быть, IMO, String errorMessage = getMessage().getMsg(0).
Код ответа всегда (при успешном/неудачном входе в систему) 200. Единственный способ определить успешный/неуспешный вход в систему — посмотреть на успех в JSON. Я могу определить с помощью
status, был ли вход пользователя успешным/неудачным, но когда вход пользователя завершился неудачно, я не могу получить доступ к сообщению об ошибке, используя его модель