Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson - Serialize any null value to empty string [duplicate]

Tags:

java

gson

I'm using gson to serialize some object. I have a requirement that any null field should be treated as an empty string, independent on the variable being a string, double or a pojo.

I tried to create a custom serializer for Object and simply return a new JsonPrimitive("") for the null valued objects, but the problem is how to handle the non-null valued objects without the use of "instanceof" or "getClass" and handling every single type.

Any thoughts on how to do this is appreciated.

like image 602
anony115511 Avatar asked Aug 14 '26 04:08

anony115511


1 Answers

This can be done using a custom TypeAdaptor for your model Object.

You can iterate over the object field using reflection and whenever a field is null, set the value in the json representation to an empty string whenever you cross a null field.

This would absolutely be hard to maintain and should be done with some risks as @Sotirios Delimanolis stated, What if the corresponding reference is not a String, how are you going to intending to handle it back and forth?

  • Here is a bean structure just used to showcase the situation:
public class MyEntity
{
  private int id;
  private String name;
  private Long socialNumber;
  private MyInnerEntity innerEntity;

  public MyEntity(int id, String name, Long socialNumber, MyInnerEntity innerEntity)
  {
    this.id = id;
    this.name = name;
    this.socialNumber = socialNumber;
    this.innerEntity = innerEntity;
  }

  public int getId()
  {
    return id;
  }

  public String getName()
  {
    return name;
  }

  public Long getSocialNumber()
  {
    return socialNumber;
  }

  public MyInnerEntity getInnerEntity()
  {
    return innerEntity;
  }

  public static class MyInnerEntity {
    @Override
    public String toString()
    {
      return "whateverValue";
    }
  }
}
  • Here is the TypeAdapter implementation which set any null value to and empty "" String:
public class GenericAdapter extends TypeAdapter<Object>
{
  @Override
  public void write(JsonWriter jsonWriter, Object o) throws IOException
  {
    jsonWriter.beginObject();
    for (Field field : o.getClass().getDeclaredFields())
    {
      Object fieldValue = runGetter(field, o);
      jsonWriter.name(field.getName());
      if (fieldValue == null)
      {
        jsonWriter.value("");
      }
      else {
        jsonWriter.value(fieldValue.toString());
      }
    }
    jsonWriter.endObject();
  }

  @Override
  public Object read(JsonReader jsonReader) throws IOException
  {
    /* Don't forget to add implementation here to have your Object back alive :) */
    return null;
  }

  /**
   * A generic field accessor runner.
   * Run the right getter on the field to get its value.
   * @param field
   * @param o {@code Object}
   * @return
   */
  public static Object runGetter(Field field, Object o)
  {
    // MZ: Find the correct method
    for (Method method : o.getClass().getMethods())
    {
      if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
      {
        if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
        {
          try
          {
            return method.invoke(o);
          }
          catch (IllegalAccessException e)
          { }
          catch (InvocationTargetException e)
          { }
        }
      }
    }
    return null;
  }
}
  • Now a simple straightforward main method to add the adapter to Gson:
public class Test
{
  public static void main(String[] args)
  {
    Gson gson = new GsonBuilder().registerTypeAdapter(MyEntity.class, new GenericAdapter()).create();
    Object entity = new MyEntity(16, "entity", (long)123, new MyEntity.MyInnerEntity());
    String json = gson.toJson(entity);
    System.out.println(json);

    Object entity2 = new MyEntity(0, null, null, null);
    json = gson.toJson(entity2);
    System.out.println(json);
  }
}

This would result in below output:

{"id":"16","name":"entity","socialNumber":"123","innerEntity":"whateverValue"}
{"id":"0","name":"","socialNumber":"","innerEntity":""}

Note that whatever the object is of type, its value is set to "" in the marshalled json string.

like image 166
tmarwen Avatar answered Aug 16 '26 17:08

tmarwen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!