1

I'm using an api where a particular field (below) normally contains a string array. However, if the array is empty, the api returns an empty object in what is normally the array of string. Here is the field that's causing problems.

Normal.

"a": [
    "str"
    ]

Empty.

"a": [
    {}
    ]

The second case causes Gson to crash with a JsonSyntaxException. How do I handle this?

2
  • So this is a field in some object not the whole object? Commented Oct 20, 2018 at 15:02
  • Yes that's right. Edited. Commented Oct 20, 2018 at 15:06

2 Answers 2

1

I don't know if this is the best way, but it works.

The faulty field can be annotated with @JsonAdapter(MyTypeAdapter.class). The TypeAdapter can then use its read method and check using peek() weather or not the next value is of the expected type.

Sign up to request clarification or add additional context in comments.

2 Comments

This is a great option also did not know about that annotation earlier. It still might be a bit easier to do with JsonDeserializer, updated my answer.
It looks to be that they're about equal in terms of difficulty. Either way I learnt something new. :)
1

Let us assume you have a class representing the API response, like:

public class Response {
    private String[] a;
    private String b;
    private String c;
}

One way to get the Response object parsed whether JSON for a is valid or not is to create a JsonDeserializer that checks if a can parsed and excludes parsing of a if it fails, so leaves a to null.

public class SkipBadSyntaxDeserializer implements JsonDeserializer<Response> {

    // This strategy is used if parse of field a fails
    private final ExclusionStrategy excludeA = new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            return "a".equals(f.getName());
        }

        // no need to care of this used only here for the Response class
        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return false;
        }
    };

    // one parser for good and another for bad format
    private final Gson gson = new Gson(),
            gsonBadFormat = new GsonBuilder()
                    .addDeserializationExclusionStrategy(excludeA).create();;

    @Override
    public Response deserialize(JsonElement json, Type typeOfT, 
                JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return gson.fromJson(json, Response.class);
        } catch (JsonSyntaxException e) {
            // parse a failed try again without it  
            return gsonBadFormat.fromJson(json, Response.class);
        }

    }

}

Try it with:

new GsonBuilder().registerTypeAdapter(Response.class,
            new SkipBadSyntaxDeserializer())
                 .create()
                 .fromJson(JSON, Response.class);

If JSON would be like:

{
    "a": [{}],
    "b": "bval",
    "c": "cval"   
}

then properties for Response would be:

a=null
b="bval"
c="cval"

Update

Based on your own answer: if it is possible to alter DTO for response then using annotation @JsonAdapter will let you to handle this per field. Deserializer will then be simply:

public class SkipExceptionAdapter implements JsonDeserializer<String[]> {
    @Override
    public String[] deserialize(JsonElement json, Type typeOfT,
                JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return context.deserialize(json, String[].class);
        } catch (JsonSyntaxException e) {
            return new String[] {}; // or null how you wish
        }
    }
}

and annotation in Response.a

@JsonAdapter(SkipExceptionAdapter.class)
private String[] a;

will handle it for that field only.

4 Comments

This is a step in the right direction. Unfortunately it seems that all fields of the problematic type are skipped. I still need to populate the fields that do contain data, not skipping the type alltogether.
@jami It should skip only the problematic field a not all fields.Need to test it again.
@jami No problem that I could see. Updated Response and added what I tested.
Strange. I was looking at my data and while gson no longer crashes, this field was empty in every case. I'll experiment more tomorrow. Thanks Pirho.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.