簡體   English   中英

Gson 僅當不是 null 或不為空時序列化字段

[英]Gson Serialize field only if not null or not empty

我有需要將 java object 轉換為 json 的要求。

我為此使用 Gson,但我需要轉換器僅序列化非 null 或非空值。

例如:

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

現在我的 Gson 實例將這個 object 轉換為 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 序列化 class 會很好。

創建你自己的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是番石榴類。 如果您不想要這種依賴,您可以自行檢查。

我個人不喜歡在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 塊中額外編碼。

在我看來,問題不在於 gson。 Gson 正確跟蹤 null 和空字符串之間的差異。 您確定要消除這種區別嗎? 您確定所有使用 TestObject 的類都不關心嗎?

如果您不關心差異,您可以做的是在序列化之前將 TestObject 中的空字符串更改為 null。 或者更好的是,使 TestObject 中的 setter 將空字符串設置為 null; 這樣您就可以在類中嚴格定義空字符串與 null 相同。 您必須確保不能在 setter 之外設置這些值。

我遇到了同樣的問題並找到了 2 個不同的解決方案


  1. 為每個字段編寫自定義 TypeAdapter class

字符串 class 的 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 字符串之前手動處理 object

似乎對任何事情都有效,還沒有測試性能:

public static boolean removeEmpty(JSONObject source) {
    
    if (null == source || source.length() == 0) {
        return true;
    }
    
    boolean isJsonObjectEmpty = false; 

    for (String key : JSONObject.getNames(source)) {
        Object value = source.get(key);
        
        boolean isValueEmpty = isValueEmpty(value);
        if(isValueEmpty) {
            source.remove(key);
        }
    }
    
    if(source.length() == 0) {
        isJsonObjectEmpty = true;
    }
    
    return isJsonObjectEmpty;
}

private static boolean isValueEmpty(Object value) {

    if (null == value) {
        return true;
    }
    
    if (value instanceof JSONArray) {
        
        JSONArray arr =  (JSONArray) value;
        if(arr.length() > 0) {
            
            List<Integer> indextesToRemove = new ArrayList<>();
            for(int i = 0; i< arr.length(); i++) {
                
                boolean isValueEmpty = isValueEmpty(arr.get(i));
                if(isValueEmpty) {
                    indextesToRemove.add(i);
                };
            }
            
            for(Integer index : indextesToRemove) {
                arr.remove(index);
            }
            
            if(arr.length() == 0) {
                return true;
            }
            
        } else {
            return true;
        }
        
    } else if (value instanceof JSONObject) {
    
        return removeEmpty((JSONObject) value);
         
    } else {
        
        if (JSONObject.NULL.equals(value) 
            || null == value 
            || value.toString().trim().length() == 0)
        ) {
            return true;
        }
    }
    
    return false;
}

采用:

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("");
        
        // if you are not using Type Adapters for your fields
        JSONObject aJSONObject1 = new JSONObject(aDoggo);
        removeEmpty(aJSONObject1);
        String jsonString1 = aJSONObject1.toString();

        // if you are using Type Adapters for your fields
        Gson gsonParser = new Gson();
        JSONObject aJSONObject2 = new JSONObject(gsonParser .toJson(aDoggo));
        removeEmpty(aJSONObject2);
        String jsonString2 = aJSONObject2.toString();
    }
}        

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM