有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

仅当不为null或不为空时,java 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 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序列化类的建议就好了


共 (3) 个答案

  1. # 1 楼答案

    创建自己的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
        }
    }
    

    然后您可以将其注册到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));
    

    产生

     {"test1":"test1"}
    

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

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

  2. # 2 楼答案

    我个人不喜欢TypeAdapter使用答案的地方是,您需要描述整个类中可能有50个字段的每个字段(这意味着TypeAdapter中有50个if块)
    我的解决方案是基于Reflection的,默认情况下,事实Gson不会序列化空值字段
    我有一个特殊的类,它保存API创建文档所需的数据,名为DocumentModel,它有大约50个字段,我不喜欢向服务器发送带有“”(空但非空)值或空数组的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;
    }
    

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

  3. # 3 楼答案

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

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