Обработка нескольких динамических типов данных в JSON

Вот мой пример 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.

2
0
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У вас есть доступ к кодам сетевых ошибок и ответов? Таким образом, вы можете создать оператор 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;

}

}

Код ответа всегда (при успешном/неудачном входе в систему) 200. Единственный способ определить успешный/неуспешный вход в систему — посмотреть на успех в JSON. Я могу определить с помощью status, был ли вход пользователя успешным/неудачным, но когда вход пользователя завершился неудачно, я не могу получить доступ к сообщению об ошибке, используя его модель

Skyyy 07.02.2019 15:08

Хорошо я понял. Вот идея: после получения ответа используйте библиотеку JSONObject, чтобы запросить результат status, а затем сформулируйте оператор переключения, чтобы определить вашу десериализацию.

Jendorski Labs 07.02.2019 15:41

Плохо, я только что понял, что у меня есть другой код ответа 200 для успешного входа и 207 для неудачного входа. Но как мне передать Custom CoverterFactory внутри метода onResponse или есть способ определить код ответа до этого? На данный момент, на основе состояния успеха/ошибки, я вручную десериализую ответ, используя new Gson().fromJson(data, DataResponse.class);.

Skyyy 08.02.2019 11:09

Также, когда не удалось войти в систему (POJO, который я создал онлайн), я получаю исключение nullPointerException при доступе к методу getMsg (после передачи JSON в десериализаторе)

Skyyy 08.02.2019 11:11

Если вы используете retrofit, вы можете получить errorCode из кода ответа # и из методов onResponse и onError, чтобы вы могли поместить метод switchToDeserialise в оба обратных вызова. По отношению к NPE, который вы получаете от getMsg, должно быть, IMO, String errorMessage = getMessage().getMsg(0).

Jendorski Labs 09.02.2019 19:16

Другие вопросы по теме