[英]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.