[英]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 個不同的解決方案
字符串 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);
}
}
似乎對任何事情都有效,還沒有測試性能:
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.