问题
Map < String , Object > jsonMap = new HashMap< String , Object>();
jsonMap.put("a",1);
jsonMap.put("b","");
jsonMap.put("c",null);
jsonMap.put("d","wuzhuti.cn");
String str = JSONObject.toJSONString(jsonMap);
System.out.println(str);
//输出结果:{"a":1,"b":"",d:"wuzhuti.cn"}
解决
从输出结果可以看出,null对应的key已经被过滤掉;这明显不是我们想要的结果,这时我们就需要用到fastjson的SerializerFeature序列化属性
也就是这个方法:JSONObject.toJSONString(Object object, SerializerFeature… features)
Fastjson的SerializerFeature序列化属性
名称 | 含义 |
UseSingleQuotes | 输出key时是否使用双引号,默认为true |
UseSingleQuotes | 使用单引号而不是双引号,默认为false |
PrettyFormat | 结果是否格式化,默认为false |
DisableCircularReferenceDetect | 消除对同一对象循环引用的问题,默认为false |
WriteMapNullValue | 是否输出值为null的字段,默认为false |
WriteNullNumberAsZero | List字段如果为null,输出为[],而非null |
WriteNullListAsEmpty | List字段如果为null,输出为[],而非null |
WriteNullStringAsEmpty | 字符类型字段如果为null,输出为”“,而非null |
WriteNullBooleanAsFalse | Boolean字段如果为null,输出为false,而非null |
WriteEnumUsingToString | Enum输出name()或者original,默认为false |
UseISO8601DateFormat | Date使用ISO8601格式输出,默认为false |
SkipTransientField | 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true |
SortField | 按字段名称排序后输出。默认为false |
WriteTabAsSpecial | 把\t做转义输出,默认为false 不推荐 |
WriteClassName | 序列化时写入类型信息,默认为false。反序列化是需用到 |
WriteSlashAsSpecial | 对斜杠’/’进行转义 |
BrowserCompatible | 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false |
WriteDateUseDateFormat | 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat); |
DisableCheckSpecialChar | 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false |
Map < String , Object > jsonMap = new HashMap< String , Object>();
jsonMap.put("a",1);
jsonMap.put("b","");
jsonMap.put("c",null);
jsonMap.put("d","wuzhuti.cn");
String str = JSONObject.toJSONString(jsonMap,SerializerFeature.WriteMapNullValue);
System.out.println(str);
//输出结果:{"a":1,"b":"","c":null,"d":"wuzhuti.cn"}
疑问:如果把WriteNullStringAsEmpty也加进去,为什么不起作用??
目前的解决办法是加一个过滤器
Map< String , Object > jsonMap = new HashMap< String , Object>();
jsonMap.put("a",1);
jsonMap.put("b","");
jsonMap.put("c",null);
jsonMap.put("d","wuzhuti.cn");
String str = JSONObject.toJSONString(jsonMap,filter);
System.out.println(str);
//输出结果:{"a":1,"b":"","c":"","d":"wuzhuti.cn"}
关于WriteNullStringAsEmpty无效的疑问:
- SerializerFeature.WriteMapNullValue 是否输出值为null的字段,默认为false
也就是说有null时会输出 而不是忽略(默认策略是忽略,所以看不到为null的字段) - WriteNullStringAsEmpty—字符类型字段如果为null,输出为”“,而非null
注意是 字段 是 字段,而不是json.put(“key”,null),所以用它时,字段为null的可以转换为空字符串。
列举的大部分SerializerFeature主要是针对Object对象序列化转换时的情况(这个时候才能判断参数的类型),而在Map中,你放进入了null就是null,进行序列化时已经没法判断它原来的类型了,所以并没有起作用。要使用SerializerFeature里相关null的参数,应该传入对象进行序列化 - 如果让输出的json中所有为null的字符串都变成空字符串,最简单的做法就是加一个值过滤器,这样就避免了有的字段为null,有的字段为空字符的现象。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
public class FormatJson {
public class Student {
private String name;
private int age;
private boolean isMale;
private Student gf;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public boolean isMale() {return isMale;}
public void setMale(boolean isMale) {this.isMale = isMale;}
public Student getGf() {return gf;}
public void setGf(Student gf) {this.gf = gf;}
}
private static ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object obj, String s, Object v) {
if (v == null)
return "";
return v;
}
};
private static SerializerFeature[] features = {
SerializerFeature.PrettyFormat,
SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.DisableCircularReferenceDetect //消除循环引用
};
public static void main(String[] args) {
new FormatJson().foo();
new FormatJson().bar();
}
private void foo() {
System.out.println("foo()---------------------------");
JSONObject j1 = new JSONObject();
j1.put("name", "zhangsan");
j1.put("age", 13);
j1.put("isMale", true);
j1.put("gf", null);
Map<String, Object> fav = new HashMap<String, Object>();
Set<String> books = new HashSet<String>();
books.add("三国");
books.add("史记");
fav.put("history", books);
String[] arts = new String[] {};
fav.put("arts", arts);
String[] musics = new String[] { "北京欢迎你", "画心" };
fav.put("musics", musics);
List<String> sports = new ArrayList<String>();
fav.put("sports", sports);
j1.put("fav", fav);
List<Student> classmates = new ArrayList<Student>();
classmates.add(new Student());
Student lisi = new Student();
lisi.setMale(false);
lisi.setAge(11);
classmates.add(lisi);
Student zhangsan = new Student();
zhangsan.setAge(13);
zhangsan.setName("张三");
zhangsan.setMale(true);
zhangsan.setGf(lisi);
classmates.add(zhangsan);
j1.put("classmates", classmates);
String str = null;
j1.put("str", str);
System.out.println(j1.toString());
System.out.println(JSON.toJSONString(j1, features));
}
private void bar() {
System.out.println("bar()---------------------------");
Student zhangsan = new Student();
zhangsan.setAge(13);
zhangsan.setName("张三");
zhangsan.setMale(true);
Student lisi = new Student();
// lisi.setName("lisi");
lisi.setMale(false);
lisi.setAge(11);
zhangsan.setGf(lisi);
System.out.println(
JSON.toJSONString(zhangsan, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty));
System.out.println(JSON.toJSONString(zhangsan, SerializerFeature.WriteMapNullValue));
System.out.println(JSON.toJSONString(zhangsan, SerializerFeature.WriteNullStringAsEmpty));
System.out.println(JSON.toJSONString(zhangsan));
System.out.println(JSON.toJSONString(zhangsan, filter));
System.out.println(JSON.toJSONString(zhangsan, filter, SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty));
}
参考: https://developer.aliyun.com/ask/64827?spm=a2c6h.13159736