java Gson仅在非空值或非空时序列化字段

bkkx9g8r  于 2022-12-02  发布在  Java
关注(0)|答案(4)|浏览(145)

我需要将Java对象转换为JSON。
我使用Gson,但我需要转换器只序列化非空值或非空值。
例如:

//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序列化类将是好的。

nzk0hqpo

nzk0hqpo1#

Create your own 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 = 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 GsonBuilder class has a bunch of methods to create your own serialization/deserialization strategies, register type adapters, and set other parameters.
Strings is a Guava class. You can do your own check if you don't want that dependency.

vulvrdjw

vulvrdjw2#

我个人不喜欢在TypeAdapter中使用answer,因为你需要描述整个类的每个字段,比如说50个字段(这意味着在TypeAdapter中有50个if块)。
我的解决方案基于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;
}

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

xfb7svmp

xfb7svmp3#

在我看来,问题并不在gson。Gson正确地记录了null和空字符串之间的区别。您确定要消除这种区别吗?您确定所有使用TestObject的类都不在乎吗?
如果你不在乎这个区别的话,你可以在序列化TestObject之前把它里面的空字符串改为null。这样就可以在类中严格定义空字符串与null相同。您必须确保这些值不能在setter之外设置。

bksxznpy

bksxznpy4#

我遇到过同样的问题,并找到了两种不同的解决方案

1.为每个字段类编写自定义TypeAdapter
String类的TypeAdapter示例:

@SuppressWarnings("rawtypes")
public class JSONStringAdapter extends TypeAdapter {

    @Override
    public String read(JsonReader jsonReader) throws IOException {
            
        String value = jsonReader.nextString();
        if(value == null || value.trim().length() == 0) {
            return null;
        } else {
            return value;
        }
    }

    @Override
    public void write(JsonWriter jsonWriter, Object object) throws IOException {
    
        String value = String.valueOf(object);
        if(value == null || value.trim().length() == 0) {    
            jsonWriter.nullValue();
        } else {
            jsonWriter.value(value);
       }
    }
}

用途:

public class Doggo {

    @JsonAdapter(JSONStringAdapter.class)
    private String name;

    public Doggo(String name) {
        this.name = name;
    }
}

public class Main {

    public static void main(String[] args) {
        Doggo aDoggo = new Doggo("");
        String jsonString = new Gson().toJson(aDoggo);
    }
}

1.在生成JSON字符串之前手动处理对象
似乎对什么都管用,还没测试过性能:

public boolean removeEmpty(JSONObject source) {

    if (null == source || source.length() == 0 ) {
        return true;
    }
    
    boolean isEmpty = false; 

    for (String key : JSONObject.getNames(source)) {
       
        Object value = source.get(key);
        if (value instanceof JSONArray) {
            
            JSONArray arr =  (JSONArray) value;
            if(arr.length() > 0) {
                boolean arrContainsNonEmpty = false;
                for(int i = 0; i< arr.length(); i++) {
                    if(removeEmpty(arr.getJSONObject(i)) == false) {
                        arrContainsNonEmpty = true;
                };
            }
            if(!arrContainsNonEmpty) {
                source.remove(key);
            }
                
            } else {
                source.remove(key);
            }
            
        } else if (value instanceof JSONObject) {
        
            boolean objectIsEmpty = removeEmpty((JSONObject) value);
            if(objectIsEmpty) {
                source.remove(key);
            }
             
        } else {
            
            if (value == null || String.valueOf(value).trim().length() == 0) {
                source.remove(key);
            }
        }
    }
    
    if(JSONObject.getNames(source).length == 0) {
        isEmpty = true;
    }
    
    return isEmpty;
}

用途:

public class Doggo {

    private String name;

    public Doggo(String name) {
        this.name = name;
    }
}

public class Main {

    public static void main(String[] args) {
        Doggo aDoggo = new Doggo("");
        JSONObject aJSONObject = new JSONObject(aDoggo);
        removeEmpty(aJSONObject);
        String jsonString = aJSONObject.toString();
    }
}

相关问题