question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to I deserialize different json response for the same request to different bean object

See original GitHub issue

for example, for the same request, the server may return:

{
  "code":200,
  "data":{
    "xxx":"xxx"
  }
}

or:

{
  "code":666,
  "error":"error detail"
}

And I’m using Android and Retrofit, so how should I handle this desrialization task?

the above question could be summarized as: how could hanndle deserialization on different condition(the json struction of response may differ)?

Or maybe should I adjust the response structure? But many 3rdparty api return stuff just like above so It’s impossible to adjust the response structure.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5

github_iconTop GitHub Comments

4reactions
Marcono1234commented, May 31, 2021

You can solve this by implementing a custom JsonDeserializer or TypeAdapterFactory. JsonDeserializer parses the JSON data into an in-memory representation of JsonElement (and subtypes). TypeAdapterFactory creates TypeAdapter instances which read the JSON data from the stream and are therefore more efficient. However, TypeAdapterFactory can only be used if code is always the first member in the JSON data because its value is needed to determine how to parse the JSON data.

The following uses JsonDeserializer:

public class GsonTypeSelectingTest {
    static class DataBody {
        public String xxx;
        
        @Override
        public String toString() {
            return "{xxx=" + xxx + "}";
        }
    }
    
    static abstract class Response {
        // Use a constant to make sure field name here and in JsonDeserializer match
        public static final String CODE_NAME = "code";
        
        @SerializedName(CODE_NAME)
        public int code;
    }
    
    static class SuccessResponse extends Response {
        public DataBody data;
        
        @Override
        public String toString() {
            return "success{code=" + code + ",data=" + data + "}";
        }
    }
    
    static class ErrorResponse extends Response {
        public String error;
        
        @Override
        public String toString() {
            return "error{code=" + code + ",error=" + error + "}";
        }
    }
    
    static class ResponseDeserializer implements JsonDeserializer<Response> {
        public static final ResponseDeserializer INSTANCE = new ResponseDeserializer();
        
        private ResponseDeserializer() {
        }
        
        @Override
        public Response deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            // Get `code` and depending on its value choose correct subclass
            int code = json.getAsJsonObject().get(Response.CODE_NAME).getAsInt();
            if (code == 200) {
                return context.deserialize(json, SuccessResponse.class);
            } else {
                return context.deserialize(json, ErrorResponse.class);
            }
        }
    }
    
    public static void main(String[] args) {
        // Should use `static final` field to reuse Gson
        Gson gson = new GsonBuilder()
            .registerTypeAdapter(Response.class, ResponseDeserializer.INSTANCE)
            .create();
        
        System.out.println(gson.fromJson("{\"code\":200,\"data\":{\"xxx\":\"test\"}}", Response.class));
        System.out.println(gson.fromJson("{\"code\":666,\"error\":\"error-detail\"}", Response.class));
    }
}
0reactions
Marcono1234commented, Aug 12, 2022

I am closing this because I think this has been answered. Please let us know if you still have questions regarding this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

json deserialize in java for different type of variable in same ...
Option 1: If you know which api you are getting response from, you can have two classes, each holding expiry in format specific...
Read more >
Convert JSON Response Body to Java Object - Tools QA
This tutorial explains How to convert or parse JSON Response Body to Java Object (POJO) using Deserializing in Java with examples.
Read more >
Definitive Guide to Jackson ObjectMapper - Serialize and ...
In this detailed guide - learn everything you need to know about ObjectMapper. Convert JSON to and from Java POJOs, implement custom ...
Read more >
Mapping a Dynamic JSON Object with Jackson - Baeldung
In this quick tutorial, we'll learn multiple ways of mapping dynamic JSON objects into Java classes. Note that in all of the tests, ......
Read more >
Spring Restful Web Services Example with JSON, Jackson ...
Spring is one of the most widely used Java EE frameworks. ... to plugin JSON as request and response in method handler -->...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found