简体   繁体   中英

Gson: JSON to java object conversion issue if element type is dynamic

I have json String and trying to convert to Java Object using GSon where the type of one element is dynamic.

Format1:

{"success":false,"errorMessage":"Missing all necessary request parameters.","status":400}

Format2:

{"success":false,"errorMessage":{"errors":[{"code":007,"message":"Daily quota reached maximum limit"}]},"status":400}";

Tried implementing a class with 'code' and 'message' properties. But using the POJO, can handle only one scenario at a time.

Is there any other way that i can handle if element object type is dynamic (string or object in this case)

You have to make your own JsonDeserializer :

public class ErrorMessageConverter implements JsonDeserializer<List<ErrorMessage>> {
    public List<ErrorMessage> deserialize(JsonElement json, Type typeOfT,
                                          JsonDeserializationContext ctx) {
        List<ErrorMessage> vals = new ArrayList<ErrorMessage>();
        if (json.isJsonPrimitive()) {
            // handle your first case, for example:
            ErrorMessage err = new ErrorMessage(json.getAsString());
            vals.add(err);
            // in this case you will have a List which contains only one element - your String-only error
        } else if (json.isJsonObject()) {
            // handle your second case
            JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
            // work with errors - parse it to a List<ErrorMessage>
            // you have to manually iterate over array's elements and parse it one by one to avoid an inifinit loop (if you try parsing it as a List, Gson will call your converter again)
            for (JsonElement e : json.getAsJsonArray()) {
                vals.add(ctx.deserialize(e, ErrorMessage.class));
            }
        }
        return vals;
    }
}

class ErrorMessage {
    int code;
    String message;

    ErrorMessage(String message) {
        this.message = message;
    }
}

Your POJO class for the response should contain a List<ErrorMessage> errorMessage .

Don't forget to register your new converter:

gsonBuilder.registerTypeAdapter(new TypeToken<List<ErrorMessage>>() {}.getType(), new ErrorMessageConverter())

Keep this field Object in your POJO . After that when you want to use your POJO , just make a if condition as below:

    MyPojo  myPojo= new MyPojo();

    if( myPojo.getMyField() instanceof String ){
        // do something
    }
    else if(myPojo.getMyField() instanceof Map<String, Object> )
    {
        // do something
    }

Or as a second way just convert your json into Map<String,Object> after that you can get your fields by using map and of course you have to check the value field for corresponding type.

Rg.

You can use @JsonAnyGetter annotation if you can use Jackson API's

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties()
{
  return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value)
{
  this.additionalProperties.put(name, value);
}

This holds the values for unmapped contents.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM