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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18491733/
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-08-12 08:29:58  来源:igfitidea点击:

Gson Serialize field only if not null or not empty

javajsonserializationgroovygson

提问by zdesam

I have requirement where I need to convert java object to json.

我有需要将 java 对象转换为 json 的要求。

I am using Gson for that but i need the converter to only serialize the non null or not empty values.

我为此使用 Gson,但我需要转换器仅序列化非空值或非空值。

For example:

例如:

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

now my Gson instance to convert this object to json looks like

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

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

String jsonStr = gson.toJson(obj);
println jsonStr;

In the above print, the result is

在上面的打印中,结果是

{"test1":"test1", "test2":"", "otherObject":{}}

Here i just wanted the result to be

在这里,我只想结果是

{"test1":"test1"}

Since the test2 is empty and otherObject is empty, i don't want them to be serialized to json data.

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

Btw, I am using Groovy/Grails so if there is any plugin for this that would be good, if not any suggestion to customize the gson serialization class would be good.

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

采纳答案by Sotirios Delimanolis

Create your own TypeAdapter

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

You can then register it with Gson.

然后,您可以使用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));

produces

产生

 {"test1":"test1"}

The GsonBuilderclass has a bunch of methods to create your own serialization/deserialization strategies, register type adapters, and set other parameters.

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

Stringsis a Guava class. You can do your own check if you don't want that dependency.

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

回答by toto2

It seems to me the problem is not with gson. Gson correctly keeps track of the difference between null and an empty string. Are you sure you want to erase that distinction? Are you sure all classes that use TestObject don't care?

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

What you could do if you don't care about the difference is to change the empty strings to null within a TestObject before serializing it. Or better, make the setters in TestObject such that an empty string is set to null; that way you define rigidly within the class that an empty string is the same as null. You'll have to make sure the values cannot be set outside the setters.

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

回答by Stan

What I personally don't like in TypeAdapterusing answer is the fact you need to describe every field of your entire class which could have lets say 50 fields (which means 50 ifblocks in TypeAdapter).
My solution is based on Reflectionand a fact Gsonwill not serialize null values fields by default.
I have a special class which holds data for API to create document called DocumentModel, which has about 50 fields and I don't like to send Stringfields with "" (empty but not null) values or empty arrays to server. So I created a special method which returns me a copy of my object with all empty fields nulled. Note - by default all arrays in my DocumentModel instance are initialized as empty (zero length) arrays and thus they are never null, you should probably check your arrays for null before checking their length.

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

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;
}

Using this method I don't care if some fields was added or removed after this method was written or whatever. The only problem left - is checking custom type fields, which are not Stringor array, but this depends to particular class and should be extra coded in if/else blocks.

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