我需要将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序列化类将是好的。
答案 0 :(得分:20)
创建自己的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
是一个番石榴类。如果你不想要那种依赖,你可以自己检查。
答案 1 :(得分:7)
我个人不喜欢在TypeAdapter
中使用答案的事实是,您需要描述整个班级的每个字段,这些字段可以说50个字段(这意味着if
块中的50个TypeAdapter
{1}})。
我的解决方案基于Reflection
,事实Gson
默认情况下不会序列化空值字段
我有一个特殊的类,它保存API的数据以创建名为DocumentModel的文档,该文档有大约50个字段,我不喜欢将带有“”(空但非空)值的String
字段或空数组发送到服务器。所以我创建了一个特殊的方法,它返回一个我的对象的副本,所有空字段都是空的。注意 - 默认情况下,我的DocumentModel实例中的所有数组都被初始化为空(零长度)数组,因此它们永远不会为空,您应该在检查它们的长度之前检查数组是否为null。
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块中进行额外编码。
答案 2 :(得分:3)
在我看来问题不在于gson。 Gson正确地跟踪null和空字符串之间的差异。你确定要删除这种区别吗?你确定所有使用TestObject的类都不关心吗?
如果不关心差异,可以做的是在序列化之前将空字符串在TestObject中更改为null。或者更好的是,在TestObject中创建setter,使空字符串设置为null;这样你就可以在类中严格定义空字符串与null相同。您必须确保无法在设置者之外设置值。