因为你在使用
Gson gson = new GsonBuilder().serializeNulls().create();
显示空值。
要跳过显示 null,让我们试试
Gson gson = new Gson();
你可以在这里测试
public static void main(String[] args) {
Gson yourGson = new GsonBuilder().serializeNulls().create(); // this is how you create your Gson object, which shows null value
Address address = new Address(null, "New York", "US");
User user = new User("Adam", 123, address);
String userJson = yourGson.toJson(user);
System.out.println(userJson);
Gson newGson = new Gson(); // with this one, it doesn't show value
System.out.println(newGson.toJson(user));
}
更新
我尝试过几次覆盖方法 serialize,但在尝试 #5 之前它失败了
public class UserCustomSerializer implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject obj = new JsonObject();
if (src.name != null) {
obj.addProperty("name", src.name);
}
obj.addProperty("id", src.id);
if (src.address != null) {
// try #1
//JsonObject addressJsonObj = new JsonObject();
//addressJsonObj.addProperty("street", src.address.street != null ? src.address.street : null);
//addressJsonObj.addProperty("city", src.address.city != null ? src.address.city : null);
//addressJsonObj.addProperty("country", src.address.country != null ? src.address.country : null);
//obj.add("address", addressJsonObj);
// try #2
//Gson gson = new GsonBuilder().serializeNulls().create();
//JsonElement jsonElement = gson.toJsonTree(src.address);
//obj.add("address", jsonElement);
// try #3
//Gson gson2 = new GsonBuilder().serializeNulls().create();
//obj.addProperty("address", gson2.toJson(src.address));
// try #4
//Gson gson = new GsonBuilder().serializeNulls().create();
//JsonObject jsonObject = gson.toJsonTree(src.address).getAsJsonObject();
//obj.add("address", jsonObject);
// try #5
JsonObject addressJsonObj = new JsonObject();
addressJsonObj.addProperty("street", src.address.street != null ? src.address.street : "null");
addressJsonObj.addProperty("city", src.address.city != null ? src.address.city : "null");
addressJsonObj.addProperty("country", src.address.country != null ? src.address.country : "null");
obj.add("address", addressJsonObj);
}
return obj;
}
}
对于尝试 #3,我构建了不正确的字符串。
对于尝试 #1、#2 和 #4,我遇到了 null 值的问题。我搜索并找到了原因以及建议here
在 JSON“对象”(又名字典)中,有两种方式来表示缺失值:要么根本没有键/值对,要么有一个 JSON 值为 null 的键。
因此,您要么使用带有适当值的 .add,在构建 JSON 时将其转换为 null,要么您没有 .add 调用。
我的 #5 方法是检查子节点是否为空,我只是按字面添加字符串“null”,然后在构建 json 字符串时替换它
private String parseToGson(User user){
Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserCustomSerializer()).create();
return gson.toJson(user).replace("\"null\"", "null");
}
这是我定义的一些测试用例
@Test
public void children_attribute_is_null() throws Exception {
String expected = "{\"name\":\"Adam\","
+ "\"id\":123,"
+ "\"address\":{"
+ "\""+ "street\":null,"
+ "\"city\":\"New York\","
+ "\"country\":\"US"
+ "\"}"
+ "}";
Address address = new Address(null, "New York", "US");
User user = new User("Adam", 123, address);
assertEquals(expected, parseToGson(user));
Gson g = new Gson();
User usr = g.fromJson( parseToGson(user), User.class);
assertEquals("Adam", usr.name);
assertEquals(123, usr.id);
assertEquals(null, usr.address.street);
assertEquals("New York", usr.address.city);
assertEquals("US", usr.address.country);
}
@Test
public void parent_attribute_is_null() throws Exception {
String expected = "{\"name\":\"Adam\","
+ "\"id\":123" + "}";
User user = new User("Adam", 123, null);
assertEquals(expected, parseToGson(user));
Gson g = new Gson();
User usr = g.fromJson( parseToGson(user), User.class);
assertEquals("Adam", usr.name);
assertEquals(123, usr.id);
assertEquals(null, usr.address);
}
@Test
public void parent_attribute_and_children_attribute_are_null() throws Exception {
String expected = "{\"id\":123,"
+ "\"address\":{"
+ "\"street\":null,"
+ "\"city\":\"New York\","
+ "\"country\":\"US"
+ "\"}"
+ "}";
Address address = new Address(null, "New York", "US");
User user = new User(null, 123, address);
assertEquals(expected, parseToGson(user));
Gson g = new Gson();
User usr = g.fromJson( parseToGson(user), User.class);
assertEquals(null, usr.name);
assertEquals(123, usr.id);
assertEquals(null, usr.address.street);
assertEquals("New York", usr.address.city);
assertEquals("US", usr.address.country);
}
更新 #2
由于以前的版本不是通用的,我想更新答案。
对于通用,我创建了MyCustomSerializer 如下
public class MyCustomSerializer<T> implements JsonSerializer<T> {
private final Class<T> type;
public MyCustomSerializer(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
@Override
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject obj = new JsonObject();
try {
Field[] declaredFields = this.type.getDeclaredFields();
for (Field field : declaredFields) {
Object object = field.get(src);
if (object != null) {
// Here, we check for 4 types of JsonObject.addProperty
if (object instanceof String) {
obj.addProperty(field.getName(), (String) object);
continue;
}
if (object instanceof Number) {
obj.addProperty(field.getName(), (Number) object);
continue;
}
if (object instanceof Boolean) {
obj.addProperty(field.getName(), (Boolean) object);
continue;
}
if (object instanceof Character) {
obj.addProperty(field.getName(), (Character) object);
continue;
}
// This is where we check for other types
// The idea is if it is an object, we need to care its child object as well, so parse it into json string and replace the null value.
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(object);
json = json.replace("null", "\"null\""); // We have to build the string first, then replace it with our special keys. In this case, I use the string "null"
JsonObject convertedObject = new Gson().fromJson(json, JsonObject.class); // Then convert it back to json object
obj.add(field.getName(), convertedObject);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
}
主要思想仍然与以前的版本相同,但我把它变成了一个通用的。
我还添加了一些额外的属性来测试这段代码使用结果构建的字符串
{
"id":123,
"address":{
"street":null,
"city":"New York",
"country":"US",
"info":{
"zipcode":null,
"address2":"stackoverflow",
"workPlaceAddress":{
"street":null,
"companyName":"google"
}
}
}
}
要调用它,我们需要这样做
private String parseToGson(User user) {
Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new MyCustomSerializer<>(User.class)).create();
return gson.toJson(user).replace("\"null\"", "null");
}
更新 #3
由于您仍然关心您的解决方案,因此我也尝试对其进行调整
public class YourSerializer <T> implements JsonSerializer<T>{
private final Class<T> type;
public YourSerializer(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
@Override
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
Gson gson = new GsonBuilder().serializeNulls().create();
JsonObject jsonObject = gson.toJsonTree(src).getAsJsonObject();
Field[] declaredFields = this.type.getDeclaredFields();
for (Field field : declaredFields) {
try {
if(field.get(src) == null) {
jsonObject.remove(field.getName());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return jsonObject;
}
}
原因是您错误地使用了serializeNulls(),导致您的输出不正确。要更正它,您应该先registerTypeAdapter 创建您的自定义 json,然后调用 serializeNulls
private String parseToGson(User user) {
Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new YourSerializer<>(User.class)).serializeNulls().create();
return gson.toJson(user);
}
我用 update#2 测试并得到了相同的结果
{
"id":123,
"address":{
"street":null,
"city":"New York",
"country":"US",
"info":{
"zipcode":null,
"address2":"aaa",
"workPlaceAddress":{
"street":null,
"companyName":"google"
}
}
}
}