- JSON回顾
- FastJson介绍
- 依赖引入
- JSON抽象类、JSONObject类、JSONArray类
- JSON类常用方法
- JSONObject类常用方法
- JSONArray类常用方法
- FastJson的使用
- FastJson序列化API
- FashJson反序列化API
- Java对象 转 JSON串、JSON对象
- JSON串 转 Java对象、JSON对象
- JSON对象 转 Java对象、JSON串
- JSON字符串 转 List
- JSON字符串 转 Map
- SerializerFeature枚举
- @JSONField注解
- 1. @JSONField配置方式, 使用name属性
- 2. 使用format配置日期格式化
- 3. 使用serialize/deserialize指定字段是否序列化
- 4. 使用ordinal指定字段的顺序 (序列化)
- 5. 使用serializeUsing制定属性的序列化类
- 6. JSONField alternateNames
- 7. JSONField jsonDirect
- @ JSONType注解
JSON介绍, 什么是序列化, 反序列化
FastJson介绍- FastJson使用指南 Jackson的使用
FastJson 是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean
。
Fastjson 的优点
- 速度快 fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。
- 使用广泛 fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受。在2012年被开源中国评选为最受欢迎的国产开源软件之一。
- 测试完备 fastjson有非常多的testcase,在1.2.11版本中,testcase超过3321个。每次发布都会进行回归测试,保证质量稳定。
- 使用简单 fastjson的 API 十分简洁。
- 功能完备 支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展。
com.alibaba
fastjson
1.2.75
JSON抽象类、JSONObject类、JSONArray类
JSON类是JSONObject和JSONArray的父类
JSON类常用方法public abstract class JSON implements JSONStreamAware, JSONAware
parseObject方法
: 解析为对象(反序列化)parseArray方法
: 解析为集合toJSONString方法
: 转为JSON格式的字符串(序列化)toJavaObject方法
: JSON对象转为Java对象- public static String toJSONStringWithDateFormat(Object object, String dateFormat,SerializerFeature… features)
@Test public void testDateFormart() { String dateStr = JSON.toJSONStringWithDateFormat(new Date(), "yyyy-MM-dd"); System.out.println(dateStr); // "2022-08-15" }
public class JSONObject extends JSON implements Map, Cloneable, Serializable, InvocationHandler
- 由于JSONObject继承JSON类, 所以JSON抽象类的公共方法也能够使用
- 还继承了Map, 也拥有Map的一些方法
-
public JSONObject getJSONObject(int index)
: 根据JSONArray的索引index, 生成JSONObject对象 -
public JSONArray getJSONArray(int index)
: 根据JSONArray的索引index, 生成JSON类型的数组 -
public T getXxx(int index)
: 根据JSONArray的index, 获取该index的value
public class JSONArray extends JSON implements List, Cloneable, RandomAccess, Serializable
- 由于JSONArray继承JSON类, 所以JSON抽象类的公共方法也能够使用
- 也继承了List接口, 拥有List的一些方法
-
public JSONObject getJSONObject(String key)
: 根据JSON的key, 生成JSONObject对象 -
public JSONArray getJSONArray(String key)
: 根据JSON的key, 生成JSON类型的数组 -
public T getXxx(String key)
: 根据JSON的key, 获取该key的value
序列化 : 把Java对象转换为字节序列(JSON字符串)的过程。
-
JSON.toJSONString
- 序列化Java对象
public void objectToJson(){ Student student = new Student(); student.setId(1); student.setName("张三"); student.setAge(20); student.setAddress("北京市"); student.setEmail("zs@sina.com"); String jsonString = JSON.toJSONString(student); System.out.println(jsonString); }
- 序列化List集合
public void listToJson(){ Student student = new Student(); student.setId(1); student.setName("张三"); student.setAge(20); student.setAddress("北京市"); student.setEmail("zs@sina.com"); Student student2 = new Student(); student2.setId(2); student2.setName("张三2"); student2.setAge(22); student2.setAddress("北京市2"); student2.setEmail("zs2@sina.com"); List list = new ArrayList(); list.add(student); list.add(student2); String jsonString = JSON.toJSONString(list); System.out.println(jsonString); }
- 序列化Map集合
public void mapToJson(){ Student student = new Student(); student.setId(1); student.setName("张三"); student.setAge(20); student.setAddress("北京市"); student.setEmail("zs@sina.com"); Student student2 = new Student(); student2.setId(2); student2.setName("张三2"); student2.setAge(22); student2.setAddress("北京市2"); student2.setEmail("zs2@sina.com"); Map map = new HashMap(); map.put("s1",student); map.put("s2",student2); String jsonString = JSON.toJSONString(map); System.out.println(jsonString); }
反序列化: 把字节序列(JSON字符串)恢复为Java对象的过程
-
JSON.parseObject
- 反序列化Java对象
public void jsonToObject(){ String jsonString = "{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"}"; Student student = JSON.parseObject(jsonString, Student.class); System.out.println(student); }
-
JSON.parseArray
- 反序列化List集合
public void jsonToList(){ String jsonString = "[{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},{\"address\":\"北京市2\",\"age\":22,\"email\":\"zs2@sina.com\",\"id\":2,\"name\":\"张三2\"}]"; List list = JSON.parseArray(jsonString,Student.class); for (int i = 0; i JSON串
String jsonStr = JSONObject.toJSONString(Java对象实例)
@Test public void javaObj2JsonStr() { Student student = Student.builder().name("lucky").age(22).build(); //String jsonString = JSON.toJSONString(student); String jsonString = JSONObject.toJSONString(student); System.out.println(jsonString); // {"age":22,"name":"lucky"} }
Java对象–>JSON对象
JSONObject jsonObj = (JSONObject) JSONObject.toJSON(Java对象实例)
JSON串 转 Java对象、JSON对象@Test public void javaObj2JsonObj() { Student student = Student.builder().name("lucky").age(22).build(); Object obj = JSONObject.toJSON(student); JSONObject jsonObject = (JSONObject) obj; System.out.println(jsonObject); // {"name":"lucky","age":22} String name = jsonObject.getString("name"); Integer age = jsonObject.getInteger("age"); System.out.printf("name: %s, age: %d", name, age); // name: lucky, age: 22 }
JSON串–>Java对象
T obj = JSONObject.parseObject(JSON字符串, Java对象.class);
@Test public void jsonStr2JavaObj() { String stuStr = "{\"age\":22,\"name\":\"lucky\"}"; Student student = JSONObject.parseObject(stuStr, Student.class); System.out.println(student); // Student(name=lucky, age=22) }
JSON串–>JSON对象
JSONObject jsonObj = JSONObject.parseObject(JSON字符串)
JSON对象 转 Java对象、JSON串@Test public void jsonStr2JsonObj() { String stuStr = "{\"age\":22,\"name\":\"lucky\"}"; JSONObject jsonObject = JSONObject.parseObject(stuStr); System.out.println(jsonObject); // {"name":"lucky","age":22} String name = jsonObject.getString("name"); Integer age = jsonObject.getInteger("age"); System.out.printf("name: %s, age: %d", name, age); // name: lucky, age: 22 }
JSON对象–>Java对象
T obj = JSONObject.toJavaObject(JSON对象实例, Java对象.class);
@Test public void jsonObj2JavaObj() { Student student = Student.builder().name("lucky").age(22).build(); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(student); Student stu2 = jsonObject.toJavaObject(Student.class); System.out.println(stu2); // Student(name=lucky, age=22) }
JSON对象–>JSON串
String jsonStr = JSONObject.toJSONString();
JSON字符串 转 List@Test public void jsonObj2JsonStr() { Student student = Student.builder().name("lucky").age(22).build(); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(student); String jsonStr = jsonObject.toJSONString(); System.out.println(jsonStr); // {"age":22,"name":"lucky"} }
List parseArray(JSON字符串, Java对象.class)
JSON字符串 转 Map@Test public void jsonStr2List() { String jsonStr = "[{\"name\":\"lucky\",\"age\":22}, {\"name\":\"Tom\",\"age\":33}]"; List students = JSONObject.parseArray(jsonStr, Student.class); students.forEach(System.out::println); /* 输出 Student(name=lucky, age=22) Student(name=Tom, age=33) */ }
Map mapObj = JSONObject.parseObject(jsonStr, new TypeReference() { })
@Test public void jsonStr2Map() { Map map = new HashMap() {{ put("name", "lucky"); put("age", "22"); }}; String mapStr = JSONObject.toJSONString(map); System.out.println(mapStr); // {"name":"lucky","age":"22"} //Map mapObj = (Map) JSON.parse(mapStr) Map mapObj = JSONObject.parseObject(mapStr, new TypeReference() { }); System.out.println(mapObj); // {name=lucky, age=22} }
泛型反序列化
- import com.alibaba.fastjson.TypeReference;
List list = JSON.parseObject("...", new TypeReference() {});
该枚举支持序列化的一些特性数据定义:
- 枚举常量 WriteMapNullValue 序列化为null的字段
- 枚举常量 WriteNullStringAsEmpty 字段为null,序列化为""
- 枚举常量 WriteNullNumberAsZero 字段为null,序列化为0
- 枚举常量 PrettyFormat格式化输出
- 枚举常量 WriteNullBooleanAsFalse 字段值为null 输出false
- 枚举常量 WriteDateUseDateFormat 格式化日期格式
// 测试类 @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { private String name; private Integer age; private String address; }
测试
@JSONField注解public class JSONFieldTest { @Test public void testSerializerFeature() { Student stu = Student.builder().age(20).address("上海").build(); String stuJson = JSON.toJSONString(stu); System.out.println("stuJson = " + stuJson); // stuJson = {"address":"上海","age":20} String stuJson2 = JSON.toJSONString(stu, SerializerFeature.WriteMapNullValue); System.out.println("stuJson2 = " + stuJson2); // stuJson2 = {"address":"上海","age":20,"name":null} String stuJson3 = JSON.toJSONString(stu, SerializerFeature.WriteNullStringAsEmpty); System.out.println("stuJson3 = " + stuJson3); // stuJson3 = {"address":"上海","age":20,"name":""} Student stu2 = Student.builder().name("lucky").address("上海").build(); String stu2Json = JSON.toJSONString(stu2, SerializerFeature.WriteNullNumberAsZero); System.out.println("stu2Json = " + stu2Json); // stu2Json = {"address":"上海","age":0,"name":"lucky"} String stu2Json2 = JSON.toJSONString(stu2, SerializerFeature.PrettyFormat); System.out.println("stu2Json = " + stu2Json2); // 输出 /* stuJson = {"address":"上海","age":20} stuJson2 = {"address":"上海","age":20,"name":null} stuJson3 = {"address":"上海","age":20,"name":""} stu2Json = {"address":"上海","age":0,"name":"lucky"} stu2Json = { "address":"上海", "name":"lucky" } */ } }
注意:若属性是私有的,必须有set方法。否则无法反序列化。
该注解作用于方法上,字段上和参数上, 可在序列化和反序列化时进行特性功能定制.
- 注解属性 : name 序列化后的名字
- 注解属性 : ordinal序列化后的顺序
- 注解属性 : format 序列化后的格式, 对日期格式有用
- 注解属性 : serialize 是否序列化该字段
- 注解属性 : deserialize 是否反序列化该字段
- 注解属性 : serialzeFeatures 序列化时的特性定义
可以配置在Field上, 或者getter/setter方法上
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { @JSONField(name = "NAME") private String name; private Integer age; }
测试
2. 使用format配置日期格式化@Test public void testJSONFieldName() { Student stu = Student.builder().name("lucky").age(20).build(); // 序列化后的JSON中key的名字 String stuStr = JSON.toJSONString(stu); System.out.println("stuStr = " + stuStr); // stuStr = {"NAME":"lucky","age":20} // 通过@FieldName(name="xxx"),可以将JSON串中xxx,反序列化给标注注解的字段 Student stuObj = JSONObject.parseObject(stuStr, Student.class); System.out.println("stuObj = " + stuObj); // stuObj = Student(name=lucky, age=20) } //输出: //stuStr = {"NAME":"lucky","age":20} //stuObj = Student(name=lucky, age=20)
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { // 配置date序列化和反序列使用yyyy-MM-dd日期格式 @JSONField(format="yyyy-MM-dd") private Date date; }
测试
3. 使用serialize/deserialize指定字段是否序列化@Test public void testJSONFieldFormat() { Student stu = Student.builder().date(new Date()).build(); String jsonStu = JSONObject.toJSONString(stu); System.out.println("jsonStu = " + jsonStu); // jsonStu = {"date":"2022-08-15"} } //输出 //jsonStu = {"date":"2022-08-15"}
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { // 不进行反序列化 @JSONField(name = "NAME", deserialize = false) private String name; // 不进行序列化 @JSONField(name = "AGE", serialize = false) private Integer age; @JSONField(format = "yyyy/MM/dd") private Date date; }
测试
4. 使用ordinal指定字段的顺序 (序列化)@Test public void testIsSerializeAndDeSerialize() { Student stuObj = Student.builder().name("lucky").age(22).date(new Date()).build(); String stuJson = JSONObject.toJSONString(stuObj); System.out.println("stuJson = " + stuJson); // stuJson = {"NAME":"lucky","date":"2022/08/16"} Student stuObj2 = JSON.parseObject(stuJson, Student.class); System.out.println("stuObj2 = " + stuObj2); } //输出: //stuJson = {"NAME":"lucky","date":"2022/08/16"} //stuObj2 = Student(name=null, age=null, date=Tue Aug 16 00:00:00 CST 2022)
缺省fastjson序列化一个java bean,是根据FieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { @JSONField(name = "NAME") private String name; @JSONField(name = "AGE") private Integer age; private Double salary; }
测试
@Test public void testJSONFieldOrdinal() { Student stuObj = Student.builder().name("lucky").age(22).salary(999D).build(); // 正常字段的序列化顺序(根据字段首字母的顺序) String stuJson = JSON.toJSONString(stuObj); System.out.println("stuJson = " + stuJson); // stuJson = {"AGE":22,"NAME":"lucky","salary":999.0} Student stu = JSON.parseObject(stuJson, Student.class); System.out.println("stu = " + stu); // stu = Student(name=lucky, age=22, salary=999.0) // 输出 // stuJson = {"AGE":22,"NAME":"lucky","salary":999.0} // stu = Student(name=lucky, age=22, salary=999.0) }
使用ordinal属性
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { @JSONField(name = "NAME", ordinal = 2) private String name; @JSONField(name = "AGE", ordinal = 1) private Integer age; @JSONField(ordinal = 0) private Double salary; }
测试
5. 使用serializeUsing制定属性的序列化类@Test public void testJSONFieldOrdinal() { Student stuObj = Student.builder().name("lucky").age(22).salary(999D).build(); // 正常字段的序列化顺序(根据字段首字母的顺序) String stuJson = JSON.toJSONString(stuObj); System.out.println("stuJson = " + stuJson); Student stu = JSON.parseObject(stuJson, Student.class); System.out.println("stu = " + stu); // 输出 //stuJson = {"salary":999.0,"AGE":22,"NAME":"lucky"} //stu = Student(name=lucky, age=22, salary=999.0) }
在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,比如:
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { @JSONField(serializeUsing = CustomedSalarySerializer.class) private Double salary; } public class CustomedSalarySerializer implements ObjectSerializer { @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { Double salary = (Double) object; String salaryStr = salary + "元"; serializer.write(salaryStr); } }
测试代码
6. JSONField alternateNames@Test public void testJSONFieldSerializeUsing() { Student stuObj = Student.builder().salary(999.2D).build(); String stuJson = JSONObject.toJSONString(stuObj); System.out.println("stuJson = " + stuJson); // 输出 // stuJson = {"salary":"999.2元"} }
在fastjson在1.2.21版本中提供了一个借鉴自gson的特性,支持反序列化时使用多个不同的字段名称,使用的方式是配置JSONField的alternateNames。
@Data @NoArgsConstrustor @AllArgsConstrustor public class Student { private int id; @JSONField(alternateNames = {"user", "person"}) private String name; }
测试
7. JSONField jsonDirect@Test public void testJSONFieldAlternateNames() { String jsonVal0 = "{\"id\":5001,\"name\":\"Jobs\"}"; String jsonVal1 = "{\"id\":5382,\"user\":\"Mary\"}"; String jsonVal2 = "{\"id\":2341,\"person\":\"Bob\"}"; Student obj0 = JSON.parseObject(jsonVal0, Student.class); Assert.assertEquals(5001, obj0.getId()); Assert.assertEquals("Jobs", obj0.getName()); // true Student obj1 = JSON.parseObject(jsonVal1, Student.class); Assert.assertEquals(5382, obj1.getId()); Assert.assertEquals("Mary", obj1.getName()); // true Student obj2 = JSON.parseObject(jsonVal2, Student.class); Assert.assertEquals(2341, obj2.getId()); Assert.assertEquals("Bob", obj2.getName()); // true }
在fastjson-1.2.12版本中,JSONField支持一个新的配置项jsonDirect,它的用途是:当你有一个字段是字符串类型,里面是json格式数据,你希望直接输入,而不是经过转义之后再输出。
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { private int id; @JSONField(jsonDirect = true) private String other; }
测试
@ JSONType注解@Test public void testJSONFieldJsonDirect() { Student stu = Student.builder().id(1001).other("{\"name\":\"lucky\"}").build(); String stuJSON = JSON.toJSONString(stu); System.out.println("stuJSON = " + stuJSON); // 不加 @JSONField(jsonDirect = true) 输出: stuJSON = {"id":1001,"other":"{\"name\":\"lucky\"}"} // 加 @JSONField(jsonDirect = true) 输出: stuJSON = {"id":1001,"other":{"name":"lucky"}} }
该注解作用于类上 , 对该类的字段进行序列化和反序列化时的特性功能定制.
- 注解属性 : includes 要被序列化的字段.
- 注解属性 : ignores 不要被序列化的字段.
- 注解属性 : orders 序列化后的顺序.
- 注解属性 : serialzeFeatures 序列化时的特性定义.
@Data @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor @JSONType(includes = {"name", "sex"}) //序列化只序列化这两个属性成员变量 public class Student { private int id; private String name; private String sex; private String password; private String phone; } @Data @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor @JSONType(ignores = {"id", "sex"}) //不序列化这两个成员变量 public class Student2 { private int id; private String name; private String sex; private String password; private String phone; }
测试
@Test public void testFieldType() { Student stu1 = new Student(); stu1.setId(11).setName("名字1").setPassword("123456").setPhone("13502141419").setSex("男"); String stuJson1 = JSON.toJSONString(stu1); System.out.println("stuJson1 = " + stuJson1); Student2 stu2 = new Student2(); stu2.setId(11).setName("名字1").setPassword("123456").setPhone("13502141419").setSex("男"); String stuJson2 = JSON.toJSONString(stu2); System.out.println("stuJson2 = " + stuJson2); // 输出 // stuJson1 = {"name":"名字1","sex":"男"} // stuJson2 = {"name":"名字1","password":"123456","phone":"13502141419"} }