3

A client has decided to start sending empty JSON objects at the end of arrays (to help their caching facepalm) but this has caused a whole bunch of unexpected behaviour in my app.

For example this is the data I am being sent...

[{object}, {object}, {}, {object}]

I currently use GSON to deserialize data sent from the server. I have been looking into type adapters to filter out these empty objects, however I am not fully sure how to implement the filtering. Any ideas on how to skip empty objects using GSON?

4
  • 1
    Are you having problems with the actual deserialization, or are you having problems after the parsing is complete and objects have been created? Commented Mar 9, 2016 at 3:09
  • The parsing was correct ... I just was wondering if there was a way to easily ignore empty objects.... Commented Mar 9, 2016 at 3:18
  • 1
    Can you simply iterate the resulting object items and remove the ones that have missing data? Commented Mar 9, 2016 at 3:19
  • Yeah that is essentially what I ended up doing ... was kind of hoping to do it through the deserialization process but just did it post deserialization. Commented Mar 9, 2016 at 3:23

2 Answers 2

2

I solved this issue ... I had to make a TypeAdapterFactory that set empty objects to null then filtered out the nulls from the resulting list.

Here is my TypeAdapterFactory

private static class EmptyCheckTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {

        // We filter out the EmptyCheckTypeAdapter as we need to check this for emptiness!
        if (Story.class.isAssignableFrom(type.getRawType())) {
            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
            final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
            return new EmptyCheckTypeAdapter<>(delegate, elementAdapter).nullSafe();
        }
        return null;
    }

    public class EmptyCheckTypeAdapter<T> extends TypeAdapter<T> {

        private final TypeAdapter<T> delegate;
        private final TypeAdapter<JsonElement> elementAdapter;

        public EmptyCheckTypeAdapter(final TypeAdapter<T> delegate,
                                     final TypeAdapter<JsonElement> elementAdapter) {
            this.delegate = delegate;
            this.elementAdapter = elementAdapter;
        }

        @Override
        public void write(final JsonWriter out, final T value) throws IOException {
            this.delegate.write(out, value);
        }

        @Override
        public T read(final JsonReader in) throws IOException {
            final JsonObject asJsonObject = elementAdapter.read(in).getAsJsonObject();
            if (asJsonObject.entrySet().isEmpty()) {
                return null;
            }
            return this.delegate.fromJsonTree(asJsonObject);
        }
    }
}

Finally, filtered out the nulls using the following code

myDto.stories.removeAll(Collections.singleton(null));
Sign up to request clarification or add additional context in comments.

1 Comment

Not optimal to filter the list after the fact, is it possible to tell GSON to not add the null element to the list in the first place?
1

You can try this solution from here

class CollectionAdapter implements JsonSerializer<Collection<?>> {

     @Override
     public JsonElement serialize(Collection<?> src, Type typeOfSrc, JsonSerializationContext context) {
     if (src == null || src.isEmpty()) // exclusion is made here
        return null;

     JsonArray array = new JsonArray();

     for (Object child : src) {
         JsonElement element = context.serialize(child);
         array.add(element);
     }

     return array;
   }
}

Then register it

Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Collection.class, new CollectionAdapter()).create();

2 Comments

I do not need to serialize data ... can I do something similar for deserialization?
Yup, this is not at all deserialization.

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.