Skyyy
Skyyy

Reputation: 1569

Handling multiple dynamic datatype in JSON

Here is my sample JSON when a user authenticates successfully

{
    "status": "success",
    "message": "",
    "data": {
        "_id": {
            "$id": "..."
        },
        "email": "...",
        "name": "...",
        "mobile": "...",
        "mobile_status": "...",
        "email_status": "..."
    }
}

And when user credentials are wrong

{
    "status": "error",
    "message": {
        "msg": [
            "Login detail incorrect"
        ]
    },
    "data": ""
}

Notice the change in datatypes of message & data. Using retrofit fit with this I received famously error Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

To resolve this I followed this example to resolve the issue. Which did resolve the OBJECT/ARRAY issue.

I have 3 Models LoginResponse,MessageResponse,DataResponse and this is how I am trying to get access to MessageResponse & DataResponse

I'm not sure if i can even use 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));

I don't think these custom JsonDeserializer are working the way its supposed to. I'm unable to cast returned response from these JsonDeserializer. The only way I can access them as string only which isn't even a proper JSON formatted string.

Also switching back order of .addConverterFactory sometimes causes a crash when i access LoginResponse model

Upvotes: 2

Views: 137

Answers (1)

Jendorski Labs
Jendorski Labs

Reputation: 527

Do you have access to the network error & response codes?. That way, you may create a switch statement that explicitly defines how you would deserialize ANY response

For example,

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;}}

Note: The above code has not been tested.

=================================== BIT OF A CRASH EDIT REALLY =============================================================================

Based on the conversation we had, and my observation on both the success & error response, i have this un-tested code/suggestion :

    //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;

}

}

Upvotes: 2

Related Questions