Java 仅当不为null或不为空时,Gson序列化字段

Java 仅当不为null或不为空时,Gson序列化字段,java,json,serialization,groovy,gson,Java,Json,Serialization,Groovy,Gson,我需要将java对象转换为json 我正在使用Gson,但是我需要转换器只序列化非null或非空值 例如: //my java object looks like class TestObject{ String test1; String test2; OtherObject otherObject = new OtherObject(); } 现在,我的Gson实例将此对象转换为json,如下所示 Gson gson = new Gson(); TestObject

我需要将java对象转换为json

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

例如:

//my java object looks like
class TestObject{
    String test1;
    String test2;
    OtherObject otherObject = new OtherObject();
}
现在,我的Gson实例将此对象转换为json,如下所示

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

String jsonStr = gson.toJson(obj);
println jsonStr;
在上面的打印中,结果是

{"test1":"test1", "test2":"", "otherObject":{}}
在这里,我只是想得到结果

{"test1":"test1"}
因为test2是空的,而otherObject是空的,所以我不希望将它们序列化为json数据


顺便说一句,我使用的是Groovy/Grails,因此如果有任何插件可以实现这一点,那么任何定制gson序列化类的建议都是好的。

在我看来,问题不在于gson。Gson正确地跟踪null和空字符串之间的差异。你确定要消除这种区别吗?您确定所有使用TestObject的类都不关心吗


如果不关心差异,可以在序列化TestObject之前将其内的空字符串更改为null。或者更好,在TestObject中设置setter,使空字符串设置为null;这样,您就可以在类中严格定义空字符串与null相同。您必须确保不能在setter之外设置值。

创建您自己的
类型适配器

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
    }
}
产生

 {"test1":"test1"}
GsonBuilder类有一系列方法来创建您自己的序列化/反序列化策略、注册类型适配器和设置其他参数


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

我个人不喜欢使用答案的
TypeAdapter
是这样的事实:你需要描述整个类中可能有50个字段的每个字段(这意味着如果
TypeAdapter
中有50个
if
块)。
我的解决方案基于
Reflection
,而事实
Gson
默认情况下不会序列化空值字段。
我有一个特殊的类,它保存API创建文档所需的数据,名为DocumentModel,它有大约50个字段,我不喜欢向服务器发送带有“”(空但不为null)值或空数组的
String
字段。所以我创建了一个特殊的方法,它返回一个对象的副本,其中所有的空字段都为空。注意-默认情况下,我的DocumentModel实例中的所有数组都初始化为空(零长度)数组,因此它们从不为null,您可能应该在检查数组长度之前检查数组是否为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;
}

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

它如何知道
otherObject
为空?如果我的TestObject类中有其他不同的对象怎么办。例如:通常我的类将有多个不同类型的嵌入对象type@zdesam您可以在此类中执行嵌套序列化。该类完全依赖于您的
TestObject
类,因此它最适合执行其所有序列化/反序列化。没有其他组件可以检查您想要的自定义条件。由于在每个类中都可以整齐地省略空字符串,您的解决方案归结为手动执行所有操作。甚至序列化所有不需要特殊处理的字段。Gson所做的事情已经不多了。投票被否决是因为如果elses-使用反射是一种更好的方法,忽略了T@Clocker然后你必须考虑到并非所有的POJO类型都是空的定义。为每一个(或一组)创建一个适配器可以让您显式地使用,我认为这比使用反射编写所有这些规则更有用。这一点很好,但通常您不想同时使用
“”
null
。更明智的解决方案可能是避免使用
null
,而只使用
。其他库可以更好地处理空字符串,而不是空字符串。数据库可以强制NOTNULL,但不能强制“NOT empty”。++对我来说,规范化为null不是一个选项,因为我的对象仍然连接到Hibernate会话。
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;
}