Gson序列化字段仅在不为空或不为空时

zde*_*sam 28 java groovy serialization json gson

我有需要将java对象转换为json的地方.

我正在使用Gson,但我需要转换器只序列化非null或非空值.

例如:

//my java object looks like
class TestObject{
    String test1;
    String test2;
    OtherObject otherObject = new OtherObject();
}
Run Code Online (Sandbox Code Playgroud)

现在我的Gson实例将此对象转换为json看起来像

Gson gson = new Gson();
TestObject obj = new TestObject();
obj.test1 = "test1";
obj.test2 = "";

String jsonStr = gson.toJson(obj);
println jsonStr;
Run Code Online (Sandbox Code Playgroud)

在上面的印刷品中,结果是

{"test1":"test1", "test2":"", "otherObject":{}}
Run Code Online (Sandbox Code Playgroud)

在这里,我只想要结果

{"test1":"test1"}
Run Code Online (Sandbox Code Playgroud)

由于test2为空且otherObject为空,我不希望它们被序列化为json数据.

顺便说一句,我正在使用Groovy/Grails,所以如果有任何插件,这将是好的,如果没有任何建议自定义gson序列化类将是好的.

Sot*_*lis 21

创建自己的 TypeAdapter

public class MyTypeAdapter extends TypeAdapter<TestObject>() {

    @Override
    public void write(JsonWriter out, TestObject value) throws IOException {
        out.beginObject();
        if (!Strings.isNullOrEmpty(value.test1)) {
            out.name("test1");
            out.value(value.test1);
        }

        if (!Strings.isNullOrEmpty(value.test2)) {
            out.name("test2");
            out.value(value.test1);
        }
        /* similar check for otherObject */         
        out.endObject();    
    }

    @Override
    public TestObject read(JsonReader in) throws IOException {
        // do something similar, but the other way around
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以注册它Gson.

Gson gson = new GsonBuilder().registerTypeAdapter(TestObject.class, new MyTypeAdapter()).create();
TestObject obj = new TestObject();
obj.test1 = "test1";
obj.test2 = "";
System.out.println(gson.toJson(obj));
Run Code Online (Sandbox Code Playgroud)

产生

 {"test1":"test1"}
Run Code Online (Sandbox Code Playgroud)

GsonBuilder班有一堆的方法来创建自己的序列化/反序列化战略,注册类型的适配器,等参数进行设置.

Strings是番石榴类.如果您不想要这种依赖,您可以自己检查.


Sta*_*tan 8

我个人不喜欢TypeAdapter使用答案的事实是你需要描述整个班级的每个领域,这可以说50个领域(这意味着50 if个区块TypeAdapter).
我的解决方案基于Reflection并且事实上Gson默认情况下不会序列化空值字段.
我有一个特殊的类,它保存API的数据以创建名为DocumentModel的文档,该文档有大约50个字段,我不喜欢向服务器发送String带有""(空但不为空)值或空数组的字段.所以我创建了一个特殊的方法,它返回一个我的对象的副本,所有空字段都是空的.注意 - 默认情况下,我的DocumentModel实例中的所有数组都被初始化为空(零长度)数组,因此它们永远不会为空,您应该在检查其长度之前检查数组是否为null.

public DocumentModel getSerializableCopy() {
    Field fields[] = new Field[]{};
    try {
        // returns the array of Field objects representing the public fields
        fields = DocumentModel.class.getDeclaredFields();
    } catch (Exception e) {
        e.printStackTrace();
    }
    DocumentModel copy = new DocumentModel();
    Object value;
    for (Field field : fields) {
        try {
            value = field.get(this);
            if (value instanceof String && TextUtils.isEmpty((String) value)) {
                field.set(copy, null);
            // note: here array is not being checked for null!
            else if (value instanceof Object[] && ((Object[]) value).length == 0) {
                field.set(copy, null);
            } else
                field.set(copy, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    return copy;
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法我不关心在写入此方法之后是否添加或删除了某些字段.剩下的唯一问题是检查自定义类型字段,它们不是String或数组,但这取决于特定的类,应该在if/else块中进行额外编码.