一. JSON
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式
二. 主流框架介绍
2.1. Gson
- Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来
- 无依赖,不需要例外额外的jar,能够直接跑在JDK上。
- 类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
- Gson在功能上面无可挑剔,但是性能上面比FastJson有所差距。
2.2. jackSon
Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。
Jackson社区相对比较活跃,更新速度快。
- Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。
- Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式
2.3. Fastjson:
- Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。
- 无依赖,不需要例外额外的jar,能够直接跑在JDK上。
- FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。
- FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库
2.4. 总结
综上三种Json技术的比较,在项目选型的时候可以使用Google的Gson和阿里巴巴的FastJson两种并行使用,
如果只是功能要求,没有性能要求,可以使用google的Gson,
如果有性能上面的要求可以使用Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean
三. Fastjson
一个JSON库涉及的最基本功能就是序列化和反序列化。Fastjson支持java bean的直接序列化。提供了com.alibaba.fastjson.JSON这个类进行序列化和反序列化。
3.1. 类型
3.1.1. 常用类型
- JSON:fastJson的解析器,用于JSON格式字符串与JSON对象及javaBean之间的转换
- JSONObject:fastJson提供的json对象 ,相当于Map < String, Object >
- JSONArray:fastJson提供json数组对象 ,相当于List< Object >
3.1.3. JSONObject
JSONObject本质是实现了Map接口,因此可以直接向上转型给Map,JSONObject的数据是用 { } 来表示的
//示例json:{ "id" : "123", "courseID" : "huangt-test", "title" : "提交作业" }
public class JSONObject extends JSON implements Map<String, Object>
3.1.4. JSONArray
JSONArray 中是由JSONObject构成的数组,可以将
//示例json [{ "id" : "123", "courseID" : "huangt-test", "title" : "提交作业" } , { "content" : null, "beginTime" : 1398873600000 "endTime" } ] ;
public class JSONArray extends JSON implements List<Object>
//举例代码
String json = "{\"name\":\"张三\",\"age\":20,\"some\":[{\"name\":\"张一\",\"age\":\"30\"},{\"name\":\"张二\",\"age\":\"10\"}]}";
//json字符串转换成jsonObject对象
JSONObject jso = JSON.parseObject(json);
//jsonobject对象取得some对应的jsonarray数组
JSONArray someList = jso.getJSONArray("some");
//jsonarray对象通过getjsonobjext(index)方法取得数组里面的jsonobject对象
JSONObject ao = someList.getJSONObject(0);
String str = ao.getString("name");
System.out.println(str);
3.2. 函数
3.2.1. 常用函数
//将JavaBean序列化为JSON文本(常用)
public static final String toJSONString(Object object);
//把JSON文本parse为JavaBean(常用)
public static final T parseObject(String text, Class clazz);
3.2.2. 其他函数
// 把JSON文本parse成JSONObject
public static final JSONObject parseObject(String text);
// 把JSON文本parse成JSONArray
public static final JSONArray parseArray(String text);
//把JSON文本parse成JavaBean集合
public static final List parseArray(String text, Class clazz);
// 将JavaBean序列化为带格式的JSON文本
public static final String toJSONString(Object object, boolean prettyFormat);
// 把JSON文本parse为JSONObject或者JSONArray
public static final Objectparse(String text);
//将JavaBean转换为JSONObject或者JSONArray。
public static final Object toJSON(Object javaObject);
3.3. 序列化
3.3.1. 基本类型处理
int o =10;
//UseSingleQuotes 单引号
String json = JSON.toJSONString(o,SerializerFeature.UseSingleQuotes);
int k= JSON.parseObject(json,Integer.class);
System.out.println("json:"+json);
System.out.println("object:"+k);
3.3.2. 复杂类型处理
public class User{
public String username="";
public int id=0;
public ArrayList<Link> link=null;
public Map<String,Link> result=null;
}
class Link {
public String name = "";
public String phone = "";
}
//序列化和反序列化方法
//将Bean转换成json字符串
String str=JSON.toJSONString(user);
//将json字符串转换为Bean
User user=JSON.parseObject(str,User.class);
3.3.3. 泛型处理
使用TypeReference将json串转成定义好的泛型对象
public class Result<T> {
//some thing...
}
Result<User> obj = (Result<User>) JSON.parseObject(js, new TypeReference<Result<User>>(){});
3.4. 定制序列化
- 通过@JSONField定制序列化
- 通过@JSONType定制序列化
- 通过SerializeFilter定制序列化
- 通过ParseProcess定制反序列化
3.4.1. 通过@JSONField定制序列化
可以把@JSONField配置在字段或者getter/setter方法上
// 配置在字段上
public class Vo {
@JSONField(name="ID")
private Integer id;
}
// SerializeResult:{"ID":0}
// 配置在字段上
public class Vo {
private Integer id;
@JSONField(name="ID")
public Integer getId() { return id;}
//这里不一样
@JSONField(name="IDs")
public void setId(Integer value) {this.id = value;}
//
}
// SerializeResult:{"IDs":0}
方法 | 描述 |
---|---|
ordinal | 指定字段的顺序 |
name | 字段key值 |
format | 配置日期格式化 |
serialize | 指定字段是否序列化 |
deserialize | 指定字段不序列化 |
serialzeFeatures | 指定规则 |
3.4.2.通过@JSONType定制序列化
@JSONType与@JSONField区别在于,@JSONType是作用在类上的。
//配置序列化的时候,不序列化id sex
@JSONType(ignores ={"id", "sex"})
// 配置序列化的时候,序列化name 和sex
@JSONType(includes={"name","sex"})
3.4.3 通过SerializeFilter定制序列化
通过SerializeFilter可以使用扩展编程的方式实现定制序列化。fastjson提供了多种SerializeFilter:
- PropertyPreFilter 根据PropertyName判断是否序列化
- PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
- NameFilter 修改Key,如果需要修改Key,process返回值则可
- ValueFilter 修改Value
- BeforeFilter 序列化时在最前添加内容
- AfterFilter 序列化时在最后添加内容
以上的SerializeFilter在JSON.toJSONString中可以使用。
可以通过扩展实现根据object或者属性名称或者属性值进行判断是否需要序列化。例如:
PropertyFilter filter = new PropertyFilter() {
public boolean apply(Object source, String name Object value) {
if ("id".equals(name)) {
int id = ((Integer) value).intValue();
return id >= 100;
}
return false;
}
};
JSON.toJSONString(obj, filter); // 序列化的时候传filter
3.4.4 通过ParseProcess定制反序列化
ParseProcess是编程扩展定制反序列化的接口。fastjson支持如下ParseProcess:
- ExtraProcessor 用于处理多余的字段
- ExtraTypeProvider 用于处理多余字段时提供类型信息
使用ExtraProcessor 处理多余字段
public static class VO {
private int id;
private Map<String, Object> attributes = new HashMap<String, Object>();
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public Map<String, Object> getAttributes() { return attributes;}
}
ExtraProcessor processor = new ExtraProcessor() {
public void processExtra(Object object, String key, Object value) {
VO vo = (VO) object;
vo.getAttributes().put(key, value);
}
};
VO vo = JSON.parseObject("{\"id\":123,\"name\":\"abc\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals("abc", vo.getAttributes().get("name"));
使用ExtraTypeProvider 为多余的字段提供类型
public static class VO {
private int id;
private Map<String, Object> attributes = new HashMap<String, Object>();
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public Map<String, Object> getAttributes() { return attributes;}
}
class MyExtraProcessor implements ExtraProcessor, ExtraTypeProvider {
public void processExtra(Object object, String key, Object value) {
VO vo = (VO) object;
vo.getAttributes().put(key, value);
}
public Type getExtraType(Object object, String key) {
if ("value".equals(key)) {
return int.class;
}
return null;
}
};
ExtraProcessor processor = new MyExtraProcessor();
VO vo = JSON.parseObject("{\"id\":123,\"value\":\"123456\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals(123456, vo.getAttributes().get("value")); // value本应该是字符串类型的,通过getExtraType的处理变成Integer类型了。
问题
1. 如何处理超大JSON数组
先调用startArray函数,然后再遍历对象,最后调用endArray
//序列化
JSONWriter writer = new JSONWriter(new FileWriter("/tmp/hello.json"));
writer.startArray();
for (int i = 0; i < 1000 * 1000; ++i) {
writer.writeValue(new Model());
}
writer.endArray();
writer.close();
//反序列化
JSONReader reader = new JSONReader(new FileReader("/tmp/hello.json"));
reader.startArray();
while (reader.hasNext()) {
VO vo = reader.readObject(VO.class);
System.out.println(vo);
}
reader.endArray();
reader.close();
2. 超大JSON对象处理
//序列化
JSONWriter writer = new JSONWriter(new FileWriter("/tmp/hello.json"));
writer.startObject();
for (int i = 0; i < 1000 * 1000; ++i) {
writer.writeKey("x" + i);
writer.writeValue(new VO());
}
writer.endObject();
writer.close();
//反序列化
JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startObject();
while(reader.hasNext()) {
String key = reader.readString();
VO vo = reader.readObject(VO.class);
//处理..
}
reader.endObject();
reader.close();
3. 处理日期
fastjson处理日期的API很简单,例如:
JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")
使用ISO-8601日期格式
JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);
全局修改日期格式
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
反序列化能够自动识别如下日期格式:
- ISO-8601日期格式
- yyyy-MM-dd
- yyyy-MM-dd HH:mm:ss
- yyyy-MM-dd HH:mm:ss.SSS
- 毫秒数字
- 毫秒数字字符串
- .NET JSON日期格式
- new Date(198293238)
4. 序列化不输出空值
使用SerializerFeature来输出空值
SerializerFeature | 描述 |
---|---|
WriteNullListAsEmpty | 将Collection类型字段的字段空值输出为[] |
WriteNullStringAsEmpty | 将字符串类型字段的空值输出为空字符串 “” |
WriteNullNumberAsZero | 将数值类型字段的空值输出为0 |
WriteNullBooleanAsFalse | 将Boolean类型字段的空值输出为false |
//示例代码
String text = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);