1

I'm using GSON with Retrofit. I want to disable empty array field deserialization.

DTO:

public class Entity implements Serializable {

    @SerializedName("body")
    @Expose
    private BodyObject body;

I work with a rest API. If the body field is empty then it send empty Array:

{
"body": []
}

Exception:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 443 path $.body

If the body is filled, then they send the correct Object.

{
  "body":  {
    "und": [
        {
        "value": "Test ....",
        "summary": "",
        "format": "filtered_html",
        "safe_value": "<p>Test ....</p>\n",
        "safe_summary": ""
        }
    ]
  }
}

-

Gson gson = new GsonBuilder()
                .setLenient()
                .create();

How can I delete, or disable these empty arrays deserializations?

Dharmishtha
  • 1,313
  • 10
  • 21
vihkat
  • 895
  • 3
  • 13
  • 28
  • Is the serialization to `JSON` done by you and the `GSON` object which is builded at the end of your question? Can you attach the `BodyObject`? – pirho Dec 16 '17 at 14:07

3 Answers3

3

As Alrama hinted you could avoid this situation by creating your own JsonDeserializer.

Something like

public class BodyObjectDeserializer implements JsonDeserializer<BodyObject> {
   @Override
   public BodyObject deserialize(JsonElement json, Type typeOfT
                                ,JsonDeserializationContext context)
         throws JsonParseException {
      try {
         return new Gson().fromJson(json, typeOfT);
      } catch (JsonSyntaxException e) {
         log.warn("Body seems empty: {}",e.getMessage());
      }
      return null;
   }
}

and registering it with your GSON that you use to de-serialize.

Gson gson = new GsonBuilder()
      .setLenient() // maybe you do not need this
      .registerTypeAdapter(BodyObject.class, new BodyObjectDeserializer())
      .create();
pirho
  • 11,565
  • 12
  • 43
  • 70
  • 1
    It is suitable only for one class. If you have hundred, and some of them are nested, it cannot help so simply. – CoolMind Feb 13 '19 at 09:01
  • @CoolMind Yes this example is a bit restricted. But you could also implement a generic `TypeAdapterFactory` to handle every type. However these kind of things are anyway hacks. The JSON should be proper. – pirho Feb 13 '19 at 09:19
  • I agree with you! Currently I am searching a solution for tens of those classes... – CoolMind Feb 13 '19 at 09:26
  • 1
    @CoolMind Put a question about it. Maybe your problem is something I or someboby else can help with. – pirho Feb 13 '19 at 10:07
  • Thanks. Please, see https://stackoverflow.com/questions/54668805/delete-empty-arrays-in-gson. – CoolMind Feb 13 '19 at 11:14
1

That's my way to skip/clear empty JSON arrays in GSON deserialize:

class MyResponseDeserializer implements JsonDeserializer<MyResponse>
{
    @Override
    public MyResponse deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
            throws JsonParseException
    {
        JsonObject obj = je.getAsJsonObject();
        if (obj.get("payload").isJsonArray())
        {
            obj.remove("payload");
        }

        return new Gson().fromJson(obj, MyResponse.class );
    }
}

...

or

class MyResponseDeserializer implements JsonDeserializer<MyResponse>
{
    private void recScan( JsonObject obj )
    {
        Iterator<Map.Entry<String, JsonElement>> iter = obj.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, JsonElement> entry = iter.next();
            JsonElement el = entry.getValue();
            if (el.isJsonArray() && (el.getAsJsonArray().size() == 0)) {
                iter.remove();
                obj.remove(entry.getKey());
            } else
            if (el.isJsonObject()) {
                recScan(el.getAsJsonObject());
            }
        }
    }

    @Override
    public MyResponse deserialize(JsonElement je, Type type,
                                     JsonDeserializationContext jdc)
            throws JsonParseException
    {
        JsonObject obj = je.getAsJsonObject();
        recScan(obj);
        return new Gson().fromJson(obj, MyResponse.class );
    }
}

and of course attach this to Gson builder

Gson gson = new GsonBuilder()
            .registerTypeAdapter(MyResponse.class, new MyResponseDeserializer())
            .setLenient()
            .create();
felix culpa
  • 11
  • 1
  • 2
0

rest API should respect Object definition. Object never could be an Array. If you could not have rest API corrected, you could manage this object with a custom deserializer, checking first if JSON contains an empty array. GSON custom deserializer

alrama
  • 618
  • 11
  • 17