java Gson - 将任何空值序列化为空字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26041726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:12:11  来源:igfitidea点击:

Gson - Serialize any null value to empty string

javagson

提问by anony115511

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.

我正在使用 gson 来序列化某个对象。我有一个要求,任何空字段都应该被视为空字符串,独立于变量是字符串、double 或 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.

我试图为 Object 创建一个自定义序列化程序,并简单地为空值对象返回一个新的 JsonPrimitive(""),但问题是如何在不使用“instanceof”或“getClass”的情况下处理非空值对象和处理每一种类型。

Any thoughts on how to do this is appreciated.

任何关于如何做到这一点的想法表示赞赏。

回答by tmarwen

This can be done using a custom TypeAdaptorfor your model Object.

这可以使用自定义TypeAdaptor模型来完成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.

您可以使用反射遍历对象字段,并且每当字段为 时null,只要跨越空字段,就将 json 表示中的值设置为空字符串。

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?

正如@Sotirios Delimanolis 所说,绝对难以维护,并且应该冒一些风险,如果相应的引用不是 String怎么,您打算如何来回处理它?

  • Here is a bean structure just used to showcase the situation:
  • 这是一个用于展示情况的 bean 结构:
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 TypeAdapterimplementation which set any nullvalue to and empty ""String:
  • 这是TypeAdapter将任何null值设置为空"" 的实现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 mainmethod to add the adapter to Gson:
  • 现在有一个简单直接的main方法将适配器添加到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.

请注意,无论对象是什么类型,其值都在编组的 json 字符串中设置为 ""。