FastJson 介绍
是什么
fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean
使用场景
Fastjson已经被广泛使用在各种场景,包括cache存储、RPC通讯、MQ通讯、网络协议通讯、Android客户端、Ajax服务器处理程序等等
优点
速度快、功能强、简单
使用
引入FastJson依赖后,参考API就可以使用了
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>版本号</version>
</dependency>
序列化和反序列化
序列化:bean 转成 json
反序列化:json 转成 bean
将 Java 对象转换为 JSON 格式
定义一个java bean
// java bean
public class Person {
// @JSONField的作用是在对象转换成json时,使用@JSONField中的name的值作为json的字段名
@JSONField(name = "AGE")
private int age;
@JSONField(name = "FULL NAME")
private String fullName;
@JSONField(name = "DATE OF BIRTH")
private Date dateOfBirth;
public Person(int age, String fullName, Date dateOfBirth) {
super();
this.age = age;
this.fullName= fullName;
this.dateOfBirth = dateOfBirth;
}
// 标准 getters & setters
}
可以使用 JSON.toJSONString() 将 Java 对象转换换为 JSON 对象
private List<Person> listOfPersons = new ArrayList<Person>();
@Before
public void setUp() {
listOfPersons.add(new Person(15, "John Doe", new Date()));
listOfPersons.add(new Person(20, "Janette Doe", new Date()));
}
@Test
public void whenJavaList_thanConvertToJsonCorrect() {
String jsonOutput= JSON.toJSONString(listOfPersons);
}
输出结果为
// 注意这里的“AGE”使用的是java bean 的属性上的@JSONField注解的值
// 如果不适用这个注解,会默认使用属性名“age”
[
{
"AGE":15,
"DATE OF BIRTH":1468962431394,
"FULL NAME":"John Doe"
},
{
"AGE":20,
"DATE OF BIRTH":1468962431394,
"FULL NAME":"Janette Doe"
}
]
@JSONField 注解的功能
// name="AGE" 设置字段转换后的json字段的名字
// serialize=false 设置字段不参与json转换
@JSONField(name="AGE", serialize=false)
private int age;
// ordinal = 2 定义字段转换成json,在json中的顺序
@JSONField(name="LAST NAME", ordinal = 2)
private String lastName;
@JSONField(name="FIRST NAME", ordinal = 1)
private String firstName;
// format="dd/MM/yyyy" 定义字段值转换成json后的显示格式
@JSONField(name="DATE OF BIRTH", format="dd/MM/yyyy", ordinal = 3)
private Date dateOfBirth;
将java bean转换成json后输出
// 根据ordinal排序
// 设置是否参与序列化
[
{
"FIRST NAME":"Doe",
"LAST NAME":"Jhon",
"DATE OF BIRTH":"19/07/2016"
},
{
"FIRST NAME":"Doe",
"LAST NAME":"Janette",
"DATE OF BIRTH":"19/07/2016"
}
]
@JSONField 的作用对象:
- Field
- Setter 和 Getter 方法
注意:FastJson 在进行操作时,是根据 getter 和 setter 的方法进行的,并不是依据 Field 进行。
注意:若属性是私有的,必须有 set 方法。否则无法反序列化。
FastJson 还支持 BeanToArray 序列化功能
可以把 JSONArray 看成 JSONObject 对象的一个集合
@Test
public void whenGenerateJson_thanGenerationCorrect() throws ParseException {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < 2; i++) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("AGE", 10);
jsonObject.put("FULL NAME", "Doe " + i);
jsonObject.put("DATE OF BIRTH", "2016/12/12 12:12:12");
jsonArray.add(jsonObject);
}
// 上述代码向jsonArray中添加了两个jsonObject
String jsonOutput = jsonArray.toJSONString();
}
输出:
[
{
"AGE":"10",
"DATE OF BIRTH":"2016/12/12 12:12:12",
"FULL NAME":"Doe 0"
},
{
"AGE":"10",
"DATE OF BIRTH":"2016/12/12 12:12:12",
"FULL NAME":"Doe 1"
}
]
JSON 字符串转换为 Java 对象
解析json,将json字符串转换成对象
注意将json反序列化为对象时,必须要有默认无参的构造函数,否则会报异常
@Test
public void whenJson_thanConvertToObjectCorrect() {
Person person = new Person(20, "John", "Doe", new Date());
String jsonObject = JSON.toJSONString(person);
Person newPerson = JSON.parseObject(jsonObject, Person.class);
// 如果我们设置序列化为 false,则age字段不参与序列化,不会被赋值,所以断言会成功
assertEquals(newPerson.getAge(), 0);
assertEquals(newPerson.getFullName(), listOfPersons.get(0).getFullName());
}
输出:
Person [age=20, fullName=John Doe, dateOfBirth=Wed Jul 20 08:51:12 WEST 2022]
--------------------------------------------
// deserialize=false 设置该字段不参与反序列化
@JSONField(name = "DATE OF BIRTH", deserialize=false)
private Date dateOfBirth;
// 设置了不参与反序列化后,输出的结果
Person [age=20, fullName=John Doe, dateOfBirth=null]
使用 ContextValueFilter 配置 JSON 转换
在某些场景下,对Value做过滤,需要获得所属JavaBean的信息,包括类型、字段、方法等
@Test
public void givenContextFilter_whenJavaObject_thanJsonCorrect() {
ContextValueFilter valueFilter = new ContextValueFilter () {
public Object process(
BeanContext context, Object object, String name, Object value) {
// 如果名字的值是DATE OF BIRTH,则返回NOT TO DISCLOSE值
if (name.equals("DATE OF BIRTH")) {
return "NOT TO DISCLOSE";
}
// 如果值包含 John 的字段,转换成大写返回
if (value.equals("John")) {
return ((String) value).toUpperCase();
} else {
return null;
}
}
};
String jsonOutput = JSON.toJSONString(listOfPersons, valueFilter);
}
使用 NameFilter 和 SerializeConfig
NameFilter: 序列化时修改 Key。
SerializeConfig:内部是个map容器主要功能是配置并记录每种Java类型对应的序列化类
@Test
public void givenSerializeConfig_whenJavaObject_thanJsonCorrect() {
// 创建formatName 过滤器使用 NameFilter 匿名类,来处理字段名称
NameFilter formatName = new NameFilter() {
public String process(Object object, String name, Object value) {
return name.toLowerCase().replace(" ", "_");
}
};
// 新创建的过滤器与 Person 类相关联,然后添加到全局实例,它是 SerializeConfig 类中的静态属性
SerializeConfig.getGlobalInstance().addFilter(Person.class, formatName);
String jsonOutput = JSON.toJSONStringWithDateFormat(listOfPersons, "yyyy-MM-dd");
}
Fastjson 定制序列化
fastjson支持多种方式定制序列化。
- 通过@JSONField定制序列化
- 通过@JSONType定制序列化
- 通过SerializeFilter定制序列化
- 通过ParseProcess定制反序列化
通过@JSONField定制序列化
上述记录过
通过@JSONType定制序列化
和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上
通过SerializeFilter定制序列化
通过SerializeFilter可以使用扩展编程的方式实现定制序列化。fastjson提供了多种SerializeFilter:
- PropertyPreFilter 根据PropertyName判断是否序列化
- PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
- NameFilter 修改Key,如果需要修改Key,process返回值则可
- ValueFilter 修改Value
- BeforeFilter 序列化时在最前添加内容
- AfterFilter 序列化时在最后添加内容
和servlet中的过滤器时一个道理,在json和对象转换的过程中,添加各种过滤器
通过ParseProcess定制反序列化
ParseProcess是编程扩展定制反序列化的接口
- ExtraProcessor 用于处理多余的字段
- ExtraTypeProvider 用于处理多余字段时提供类型信息
使用ExtraProcessor 处理多余字段
// java bean
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 处理多余字段,此处多余字段是name
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);
}
// 如果参数key的值是value,就将值的类型转成int
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类型了。
FastJson 在Spring中使用fastJSON
FastJson 提供了Spring MVC HttpMessageConverter的实现
可在Spring Controller中使用FastJson进行数据的序列化和反序列化FastJsonConfig配置
<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
<!-- Default charset -->
<property name="charset" value="UTF-8" />
<!-- Default dateFormat -->
<property name="dateFormat" value="yyyy-MM-dd HH:mm:ss" />
<!-- Feature -->
<property name="features">
<list>
<value>Your feature</value>
</list>
</property>
<!-- SerializerFeature -->
<property name="serializerFeatures">
<list>
<value>Your serializer feature</value>
</list>
</property>
<!-- Global SerializeFilter -->
<property name="serializeFilters">
<list>
<ref bean="Your serializer filter"/>
</list>
</property>
<!-- Class Level SerializeFilter -->
<property name="classSerializeFilters">
<map>
<entry key="Your filter class" value-ref="Your serializer filter"/>
</map>
</property>
</bean>
HttpMessageConverter配置
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- MediaTypes -->
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
</list>
</property>
<!-- FastJsonConfig -->
<property name="fastJsonConfig" ref="fastJsonConfig" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler />
Fastjson 处理超大JSON文本
Fastjson当需要处理超大JSON文本时,需要Stream API
序列化
超大JSON数组序列化
如果你的JSON格式是一个巨大的JSON数组,有很多元素,则先调用startArray,然后挨个写入对象,然后调用endArray
// 创建JSONWriter对象,并设置要写入文件的位置
JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
// 表明我要写的是一个数组
writer.startArray();
for (int i = 0; i < 1000 * 1000; ++i) {
writer.writeValue(new VO());
}
writer.endArray();
writer.close();
超大JSON对象序列化
如果你的JSON格式是一个巨大的JSONObject,有很多Key/Value对,则先调用startObject,然后挨个写入Key和Value,然后调用endObject
JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
writer.startObject();// 表明要写入是对象
for (int i = 0; i < 1000 * 1000; ++i) {
writer.writeKey("x" + i);
writer.writeValue(new VO());
}
writer.endObject();
writer.close();
反序列化
超大JSON数组序列化
JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startArray();
while(reader.hasNext()) {
VO vo = reader.readObject(VO.class);
// handle vo ...
}
reader.endArray();
reader.close();
超大JSON对象序列化
JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startObject();
while(reader.hasNext()) {
String key = reader.readString();
VO vo = reader.readObject(VO.class);
// handle vo ...
}
reader.endObject();
reader.close();
常用API
序列化API
public abstract class JSON {
// 将Java对象序列化为JSON字符串,支持各种各种Java基本类型和JavaBean
public static String toJSONString(Object object, SerializerFeature... features);
// 将Java对象序列化为JSON字符串,返回JSON字符串的utf-8 bytes
public static byte[] toJSONBytes(Object object, SerializerFeature... features);
// 将Java对象序列化为JSON字符串,写入到Writer中
public static void writeJSONString(Writer writer,
Object object,
SerializerFeature... features);
// 将Java对象序列化为JSON字符串,按UTF-8编码写入到OutputStream中
public static final int writeJSONString(OutputStream os,
Object object,
SerializerFeature... features);
}
反序列化API
public abstract class JSON {
// 将JSON字符串反序列化为JavaBean
public static <T> T parseObject(String jsonStr,
Class<T> clazz,
Feature... features);
// 将JSON字符串反序列化为JavaBean
public static <T> T parseObject(byte[] jsonBytes, // UTF-8格式的JSON字符串
Class<T> clazz,
Feature... features);
// 将JSON字符串反序列化为泛型类型的JavaBean
public static <T> T parseObject(String text,
TypeReference<T> type,
Feature... features);
// 将JSON字符串反序列为JSONObject
public static JSONObject parseObject(String text);
}
// 解析树
JSONObject jsonObj = JSON.parseObject(jsonStr);
// 解析POJO
Model model = JSON.parseObject(jsonStr, Model.class);
// 解析POJO泛型
Type type = new TypeReference<List<Model>>() {}.getType();
List<Model> list = JSON.parseObject(jsonStr, type);
// 将POJO转换为json字符串
Model model = new Model();
String jsonStr = JSON.toJSONString(model);
// 将POJO作为json字符串写入OutputStream
使用示例
// 解析树
JSONObject jsonObj = JSON.parseObject(jsonStr);
// 解析POJO
Model model = JSON.parseObject(jsonStr, Model.class);
// 解析POJO泛型
Type type = new TypeReference<List<Model>>() {}.getType();
List<Model> list = JSON.parseObject(jsonStr, type);
// 将POJO转换为json字符串
Model model = new Model();
String jsonStr = JSON.toJSONString(model);
// 将POJO作为json字符串写入OutputStream
Model model = ...;
OutputStream os = JSON.writeJSONString(os, model);
// 将POJO作为json字符串写入Writer
Model model = ...;
Writer writer = ...;
JSON.writeJSONString(writer, model);
Fastjson JSONField
public @interface JSONField {
// 配置序列化和反序列化的顺序,1.1.42版本之后才支持
int ordinal() default 0;
// 指定字段的名称
String name() default "";
// 指定字段的格式,对日期格式有用
String format() default "";
// 是否序列化
boolean serialize() default true;
// 是否反序列化
boolean deserialize() default true;
}
JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化
public static class Model {
@JSONField(serializeUsing = ModelValueSerializer.class)
public int value;
}
public static class ModelValueSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
// 对model.value末尾拼接上“元”,设置为字符串类型,序列化时写出
Integer value = (Integer) object;
String text = value + "元";
serializer.write(text);
}
}
JSONField alternateNames支持反序列化时使用多个不同的字段名称,使用的方式是配置JSONField的alternateNames
public static class Model {
public int id;
// 反序列化时,字段值是"user"或者"person"时,都会被映射给name
@JSONField(alternateNames = {"user", "person"})
public String name;
}
String jsonVal0 = "{\"id\":5001,\"name\":\"Jobs\"}";
String jsonVal1 = "{\"id\":5382,\"user\":\"Mary\"}";
String jsonVal2 = "{\"id\":2341,\"person\":\"Bob\"}";
Model obj0 = JSON.parseObject(jsonVal0, Model.class);
assertEquals(5001, obj0.id);
assertEquals("Jobs", obj0.name);
Model obj1 = JSON.parseObject(jsonVal1, Model.class);
assertEquals(5382, obj1.id);
assertEquals("Mary", obj1.name);
Model obj2 = JSON.parseObject(jsonVal2, Model.class);
assertEquals(2341, obj2.id);
assertEquals("Bob", obj2.name);
JSONField支持一个新的配置项jsonDirect,它的用途是:当你有一个字段是字符串类型,里面是json格式数据,你希望直接输入,而不是经过转义之后再输出
public static class Model {
public int id;
@JSONField(jsonDirect=true)
public String value;
}
Model model = new Model();
model.id = 1001;
model.value = "{}";
String json = JSON.toJSONString(model);
Assert.assertEquals("{\"id\":1001,\"value\":{}}", json);
Fastjson JSONPath
这是一个很强大的功能,可以在java框架中当作对象查询语言(OQL)来使用
public class JSONPath {
// 求值,静态方法
public static Object eval(Object rootObject, String path);
// 计算Size,Map非空元素个数,对象非空元素个数,Collection的Size,数组的长度。其他无法求值返回-1
public static int size(Object rootObject, String path);
// 是否包含,path中是否存在对象
public static boolean contains(Object rootObject, String path) { }
// 是否包含,path中是否存在指定值,如果是集合或者数组,在集合中查找value是否存在
public static boolean containsValue(Object rootObject, String path, Object value) { }
// 修改制定路径的值,如果修改成功,返回true,否则返回false
public static boolean set(Object rootObject, String path, Object value) {}
// 在数组或者集合中添加元素
public static boolean array_add(Object rootObject, String path, Object... values);
}
List<Person> entities = new ArrayList<Person>();
entities.add(new Person("ljw2083",1));
entities.add(new Person("wenshao",2));
entities.add(new Person("yakolee",3));
entities.add(new Person(null,4));
// 返回age是2和3的
List<Object> result = (List<Object>) JSONPath.eval(entities, "[age in (2,3)]");
System.out.println(result);
// 返回enties的所有名称
List<String> names = (List<String>)JSONPath.eval(entities, "$.name");
// 返回下标为1和2的元素
List<Entity> result = (List<Entity>)JSONPath.eval(entities, "[1,2]");
// 返回下标从0到2的元素
List<Entity> result = (List<Entity>)JSONPath.eval(entities, "[0:2]");
//将id字段修改为123456
JSONPath.set(entity, "id", 123456);
//将value字段赋值为长度为0的数组
JSONPath.set(entity, "value", new int[0]);
//将value字段的数组添加元素1,2,3
JSONPath.arrayAdd(entity, "value", 1, 2, 3);
输出:
[{"age":2},{"age":3}]
Fastjson toJSONString
Fastjson 将java对象序列化为JSON字符串,fastjson提供了一个最简单的入口
Model model = new Model();
model.id = 1001;
String json = JSON.toJSONString(model);
Fastjson writeJSONString
JSON类新增对OutputStream/Writer直接支持
class Model {
public int value;
}
Model model = new Model();
model.value = 1001;
OutputStream os = ...;
JSON.writeJSONString(os, model);
JSON.writeJSONString(os, Charset.from("GB18030"), model);
Writer writer = ...;
JSON.writeJSONString(os, model);
Fastjson parseObject
fastjson新增加了对InputStream的支持
class Model {
public int value;
}
InputStream is = ...
Model model = JSON.parseObject(is, Model.class);
Model model2 = JSON.parseObject(is, Charset.from("UTF-8"), Model.class);
Fastjson BeanToArray
在fastjson中,支持一种叫做BeanToArray的映射模式。普通模式下,JavaBean映射成json object,BeanToArray模式映射为json array
Model model = new Model();
model.id = 1001;
model.name = "gaotie";
// 输出 {"id":1001,"name":"gaotie"}
String text_normal = JSON.toJSONString(model);
// 输出 [1001,"gaotie"]
String text_beanToArray = JSON.toJSONString(model, SerializerFeature.BeanToArray);
Fastjson 对象或数组转JSON
// 用户组对象转JSON串
String jsonString = JSON.toJSONString(group);
// JSON串转用户组对象
UserGroup group2 = JSON.parseObject(jsonString, UserGroup.class);
// 用户对象数组转JSON串
String jsonString2 = JSON.toJSONString(users);
// JSON串转用户对象列表
List<User> users2 = JSON.parseArray(jsonString2, User.class);
Fastjson Obejct/Map/JSON/String 互转
// 数组转json字符串
String json_arr_String = JSON.toJSONString(arr,true);
// json字符串转数组
JSONArray jsonArray = JSON.parseArray(json_arr_String);
// map转json
String json=JSON.toJSONString(map);
// json转map
Map map1 = JSON.parseObject(json);
// bean转json
String jsonString = JSON.toJSONString(person);
// json转bean
Person person =JSON.parseObject(jsonString,Person.class);
// json转集合
List<Person> persons2 = JSON.parseArray(jsonString,Person.class);