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?

fergdev
  • 963
  • 1
  • 13
  • 27
  • 1
    Are you having problems with the actual deserialization, or are you having problems after the parsing is complete and objects have been created? – Doug Stevenson Mar 09 '16 at 03:09
  • The parsing was correct ... I just was wondering if there was a way to easily ignore empty objects.... – fergdev Mar 09 '16 at 03:18
  • 1
    Can you simply iterate the resulting object items and remove the ones that have missing data? – Doug Stevenson Mar 09 '16 at 03: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. – fergdev Mar 09 '16 at 03:23

2 Answers2

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));
fergdev
  • 963
  • 1
  • 13
  • 27
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();
Community
  • 1
  • 1
Inducesmile
  • 2,475
  • 1
  • 17
  • 19