Java 中FastJson的使用【吃透FastJson】
如果不了解JSON格式,建议先看下:JSON数据格式【学习记录】
JSON序列化、反序列化JavaBean的框架有很多,最常见的Jackson、阿里巴巴开源的FastJson、谷歌的GSON、apache提供的json-lib等,下面我们主要来熟悉一下:Java语言中FastJson的使用。
FastJson
FastJson是由阿里巴巴工程师基于Java开发的一款Json解析器和生成器,可用于将Java对象转换为其JSON表示形式,它还可以用于将JSON字符串转换为等效的Java对象。FastJson可以处理任意Java对象,包括没有源代码的预先存在的对象。
FastJson使用十分简便,我们只需要在Maven工程的pom文件中引入以下依赖即可:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
- 1
- 2
- 3
- 4
- 5
FastJson API的入口是com.alibaba.fastjson.JSON
,常用的序列化操作都可以在JSON类上的静态方法直接完成。
API测试
我们已经在项目中引入了FastJson的依赖,我们再创建一个用户类用于测试:
package com.test.json;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private String sex;
private Integer age;
public User () {
}
public User(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.sex = builder.sex;
this.age = builder.age;
}
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Builder</span> <span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Builder</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">private</span> <span class="token class-name">Integer</span> id<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> sex<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">Integer</span> age<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">sex</span><span class="token punctuation">(</span><span class="token class-name">String</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>sex <span class="token operator">=</span> sex<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">id</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">User</span> <span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Builder</span> <span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Builder</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">private</span> <span class="token class-name">Integer</span> id<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> sex<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">Integer</span> age<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">sex</span><span class="token punctuation">(</span><span class="token class-name">String</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>sex <span class="token operator">=</span> sex<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Builder</span> <span class="token function">id</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">User</span> <span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
一、序列化
序列化就是将JavaBean序列化为JSON字符串,下面我们来看下FastJson常见的序列化方法。
下面序列化相关方法都有统一的返回值类型String。
1)toJsonString(Object o);
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user));
}
- 1
- 2
- 3
- 4
{"age":23,"id":1,"name":"张三","sex":"男"}
- 1
我们通过传入一个对象,便可以将对象转成JSON字符串,这里我们传入的不仅仅是JavaBean还可以是一个Map对象,传入Map对象我们同样也可以取到一个JSON字符串。
public static void main(String[] args) {
Map<String, Object> userMap = new HashMap<>();
userMap.put("id", 1);
userMap.put("name", "张三");
userMap.put("sex", "男");
userMap.put("age", 23);
System.out.println(JSON.toJSONString(userMap));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
{"age":23,"id":1,"name":"张三","sex":"男"}
- 1
List对象也很适用,结果是一个标准的JSONArray的字符串。
public static void main(String[] args) {
User zhangsan = User.build().id(1).name("张三").sex("男").age(23).build();
User lisi = User.build().id(2).name("李四").sex("女").age(18).build();
List<User> userList = new ArrayList<>();
userList.add(zhangsan);
userList.add(lisi);
System.out.println(JSON.toJSONString(userList));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
[{"id":1,"name":"张三","sex":"男","age":23},{"id":2,"name":"李四","sex":"女","age":18}]
- 1
2)toJSONString(Object o, boolean prettyFormat);
如果说 toJSONString(Object o);
的输出结果只有单调的一行让你看起来有点吃力,那么我们可以使用 toJSONString(Object o, boolean prettyFormat);
来让输出结果看起来舒服点。
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user, true));
}
- 1
- 2
- 3
- 4
{
"age":23,
"id":1,
"name":"张三",
"sex":"男"
}
- 1
- 2
- 3
- 4
- 5
- 6
通过JSON自带的格式化,让输出结果看起来更加清晰,真是贴心~
3)JSON.toJSONString(Object object, SerializerFeature… features);
我们可以看到这个方法里面有个参数SerializerFeature...
,可能感到有点陌生,我们先来看下什么是 SerializerFeature
,通过源码可以发现 SerializerFeature
原来是个枚举类:
源码中都被 @deprecated
注释的实例说明已经废弃了,那有哪些是我们平时经常用到的呢:
对象 | 描述 |
---|---|
SerializerFeature.UseSingleQuotes | 使用单引号而不是双引号,默认为false |
SerializerFeature.PrettyFormat | 结果是否格式化,默认为false |
SerializerFeature.WriteDateUseDateFormat | 如果时间是date、时间戳类型,按照这种格式"yyyy-MM-dd HH:mm"初始化时间 |
SerializerFeature.WriteMapNullValue | 是否输出值为null的字段,默认为false |
SerializerFeature.WriteClassName | 序列化时写入类型信息,默认为false |
使用案例:
SerializerFeature.UseSingleQuotes
使用单引号而不是使用双引号,默认为false。
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user, SerializerFeature.UseSingleQuotes));
}
- 1
- 2
- 3
- 4
{'age':23,'id':1,'name':'张三','sex':'男'}
- 1
SerializerFeature.PrettyFormat
结果是否格式化,默认为false。
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user));
System.out.println("===============");
System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat));
}
- 1
- 2
- 3
- 4
- 5
- 6
{"age":23,"id":1,"name":"张三","sex":"男"}
===============
{
"age":23,
"id":1,
"name":"张三",
"sex":"男"
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
SerializerFeature.WriteDateUseDateFormat
如果时间是Date、时间戳类型,按照这种格式初始化时间"yyyy-MM-dd HH:mm"。
public static void main(String[] args) {
System.out.println(JSON.toJSONString(new Date()));
System.out.println("===============");
System.out.println(JSON.toJSONString(new Date(), SerializerFeature.WriteDateUseDateFormat));
}
- 1
- 2
- 3
- 4
- 5
1676427576691
===============
"2023-02-15 10:19:37"
- 1
- 2
- 3
通过这种方式我们将日期输出成了固定的格式:yyyy-MM-dd HH:mm,有时候我们不想得到这种格式那该怎么办?通过下面方法支持自定义时间格式:(注意方法不要用错)
4)toJSONStringWithDateFormat(Object object, String dateFormat, SerializerFeature… features);
public static void main(String[] args) {
System.out.println(JSON.toJSONString(new Date()));
System.out.println("===============");
System.out.println(JSON.toJSONStringWithDateFormat(new Date(), "HH:mm:ss"));
}
- 1
- 2
- 3
- 4
- 5
1676428350771
===============
"10:32:30"
- 1
- 2
- 3
下面我们接着看SerializerFeature枚举类的其他用法。
SerializerFeature.WriteMapNullValue
是否输出值为null的字段,默认为false。
这个有什么用处呢?我们应该很清楚开发规范中鼓励用JavaBean传递参数,尽量减少Map传递参数,因为Map相当于一个黑盒,对于使用者来说根本不知道里面存在哪些字段,而对于创建者来说估计也时常会忘记里面存在哪些字段,为了解决这个痛,JSON也推出了解决方法:
public static void main(String[] args) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("name", null);
dataMap.put("age", 23);
System.out.println(JSON.toJSONString(dataMap));
System.out.println("===============");
System.out.println(JSON.toJSONString(dataMap, SerializerFeature.WriteMapNullValue));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
{"age":23}
===============
{"name":null,"age":23}
- 1
- 2
- 3
通过普通方式的 toJSONString()
方法,空值仿佛被吃掉了,这很可能会成为一个开发灾难!
SerializerFeature.WriteClassName
序列化时写入类信息,默认为false。这个方法可以在反序列化的时候用到,用法如下:
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user, SerializerFeature.WriteClssName));
}
- 1
- 2
- 3
- 4
{"@type":"com.test.json.User","age":23,"id":1,"name":"张三","sex":"男"}
- 1
通过这样我们可以看到我们序列化的对象是什么类型的。
上面这些便是toJSONString的扩展用法,上面说到的是序列化,那么对应的便是反序列化。
二、反序列化
反序列化就是把JSON格式的字符串转换为JavaBean对象。
1)JSONObject parseObject(String text);
public static void main(String[] args){
String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println(jsonObject.get("name"));
}
- 1
- 2
- 3
- 4
- 5
张三
- 1
用法十分简单,可以将一个标准的JSON字符串转为一个JSONObject对象,由于JSONObject类实现了Map接口,因此我们可以通过get()来获取到值。
我们上述已经说过Map的致命不足,所以我们更希望能得到一个JavaBean对象。
2)<T> T parseObject(String text, Class<T> clazz);
我们通过传入我们想要转换的对象类型,就可以得到我们想要的JavaBean。
public static void main(String[] args){
String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";
User user = JSON.parseObject(jsonStr, User.class);
System.out.println(user.getName());
}
- 1
- 2
- 3
- 4
- 5
张三
- 1
除了基本反序列化之外,还有一种泛型反序列化可提供使用。
3)<T> T parseObject(String text, TypeReference<T> type, Feature... features);
通过泛型,我们就可以不用传入一个Class对象,而直接获取到我们的JavaBean。
public static void main(String[] args){
String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";
User user = JSON.parseObject(jsonStr, new TypeReference<User>(){});
System.out.println(user.getName());
}
- 1
- 2
- 3
- 4
- 5
张三
- 1
FastJson序列化还有一个用处那便是进行深克隆。软件设计模式中:原型模式涉及到的深克隆和浅克隆。
浅克隆的实现方式十分简单,我们只需要实现Cloneable接口,然后重写clone()方法:
@Data
class Person {
private String name;
}
@Data
class NiceCard implements Cloneable {
public Person person;
public void award() {
System.out.println(this.person.getName() + "获得好人卡一张");
}
public NiceCard clone() throws CloneNotSupportedException {
return (NiceCard)super.clone();
}
}
public class TestClient {
public static void main(String[] args) {
NiceCard niceCard = new NiceCard();
Person person = new Person();
person.setName("小李");
niceCard.setPerson(person);
NiceCard cloneCard = niceCard.clone();
Persson clonePerson = cloneCard.getPerson();
clonePerson.setName("小王");
niceCard.award();
cloneCard.award();
System.out.println(person == clonePerson);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
小王获得一张好人卡
小王获得一张好人卡
true
- 1
- 2
- 3
结果中我们可以看到,好人卡都是属于小王的,这就是浅克隆的弊端了。
我们要想实现深克隆有许多种方式:
- 手动为引用属性赋值
- 借助FastJson
- 使用Java流的序列化对象
方法有很多,我们重点看下FastJson的实现方式:
public static void main(String[] args) {
NiceCard niceCard = new NiceCard();
Person person = new Person();
person.setName("小李");
niceCard.setPerson(person);
//借助FastJson
NiceCard cloneCard = JSON.parseObject(JSON.toJSONString(niceCard), NiceCard.class);
Person clonePerson = cloneCard.getPerson();
clonePerson.setName("小王");
niceCard.award();
cloneCard.award();
System.out.println(person == clonePerson);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
小李获得好人卡一张
小王获得好人卡一张
false
- 1
- 2
- 3
通过FastJson反序列化,我们得到的两个对象实际上是不同的,这也很方便的实现了深克隆。
4)<T> List<T> parseArray(String text, Class<T> clazz);
这是将一个JSON字符串转为JSONArray的方法。
public static void main(String[] args) {
String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"id\":2,\"name\":\"李四\",\"sex\":\"女\",\"age\":18}]";
List<User> userList = JSON.parseArray(jsonStr, User.class);
userList.forEach(System.out::println);
}
- 1
- 2
- 3
- 4
- 5
User(id=1, name=张三, sex=男, age=23)
User(id=2, name=李四, sex=女, age=18)
- 1
- 2
同样我们也可以通过使用泛型序列化来实现同样的功能:
5)List<Object> parseArray(String text, Type[] types);
public static void main(String[] args) {
String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"id\":2,\"name\":\"李四\",\"sex\":\"女\",\"age\":18}]";
Type type = new TypeReference<User>() {}.getType();
JSON.parseArray(jsonStr, new Type[]{type, type}).forEach(System.out::println);
}
- 1
- 2
- 3
- 4
- 5
这种方式有个坑就是:我们使用parseArray()这个方法的时候第二个参数需要传入我们要反序列化的对象类型,但是我们这里需要传入的是数组,不知道你有没有为数组里面放了两个一样的type感到奇怪?没错,这就是方法的坑,我们List里面有多少个对象,Type[]这个数组里面的个数要与之匹配,不然会抛出以下错误:
上述JSON串中对象的类型都为User,如果JSON串中存在不同的类型时:
public static void main(String[] args) {
String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"stuName\":\"李四\"}]";
Type userType = new TypeReference<User>() {}.getType();
Type studentType = new TypeReference<Student>() {}.getType();
JSON.parseArray(jsonStr, new Type[]{userType,studentType}).forEach(System.out::println);
}
- 1
- 2
- 3
- 4
- 5
- 6
User(id=1, name=张三, sex=男, age=23)
Student(stuName=李四)
- 1
- 2
如果将userType和studentType调换顺序,则结果:
Student(stuName=null)
User(id=null, name=null, sex=null, age=null)
- 1
- 2
三、JavaBean转换为Byte[]
我们平时在进行网络通讯的时候,需要将对象转为字节然后进行传输。
1)我们使用字符串的时候,字符串中有个很便捷的API可以将字符串转为字节数组。
String str = "张三";
byte[] bytes = str.getBytes();
- 1
- 2
2)但是我们要将一个JavaBean对象转为字节数组的时候,我们得借助ByteArrayOutputStream流的帮助。
public static void main(String[] args) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try{
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch(IOException ex) {
ex.printStackTrace();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这种方式也可以很好的将JavaBean对象转为字节数组,但是代码不免有点多了!
3)而FastJson中也提供了很方便的API以供使用(将JavaBean对象转为字节数组):
byte[] toJSONBytes(Object object, SerializerFeature... features);
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
//JavaBean对象转为字节数组
byte[] bytes = JSON.toJSONBytes(user);
}
- 1
- 2
- 3
- 4
- 5
4)FastJson也同样支持(将字节数组转为JavaBean):
<T> T parseObject(byte[] bytes, Type clazz, Feature... features);
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
//JavaBean对象转为字节数组
byte[] bytes = JSON.toJSONBytes(user);
//将字节数组转为JavaBean对象
Object obj = JSON.parseObject(bytes, User.class, Feature.IgnoreNotMatch);
System.out.println(obj);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
User(id=1, name=张三, sex=男, age=23)
- 1
从parseObject()这个方法中我们又看到了一个奇怪的参数Feature,我们点击进入源码可以发现这其实也是一个枚举类:
看的同样云里雾里的,这么多实例,以下我们对比较常用的做出了注释:
对象 | 描述 |
---|---|
AllowUnQuotedFieldNames | 决定parser是否将允许使用非双引号属性名 |
AllowSingleQuotes | 决定parser是否允许单引号来包住属性名称和字符串值 |
InternFieldNames | 决定JSON对象属性名称是否可以被String#intern 规范化表示,如果允许,则JSON所有的属性名将会 intern() ;如果不设置,则不会规范化,默认下,该属性是开放的。 |
AllowISO8601DateFormat | 设置为true则遇到字符串符合ISO8601格式的日期时,会直接转换成日期类 |
AllowArbitraryCommas | 允许多重逗号,如果设为true,则遇到多个逗号会直接跳过 |
UseBigDecimal | 设置为true则用BigDecimal类来装载数字,否则用的是double |
IgnoreNotMatch | 忽略不匹配 |
DisableCircularReferenceDetect | 禁用循环引用检测 |
InitStringFieldAsEmpty | 对于没有值得字符串属性设置为空串 |
SupportArrayToBean | 支持数组to对象 |
OrderedField | 属性保持原来的顺序 |
DisableSpecialKeyDetect | 禁用特殊字符检查 |
UseObjectArray | 使用对象数组 |
writeJSONString(OutputStream os, Object o);
这个方法是将对象写入输出流中。
public static void main(String[] args) throws IOException {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
FileOutputStream os = new FileOutputStream("D:\\test.txt");
int i = JSON.writeJSONString(os, user);
System.out.println(i); //输出45
}
- 1
- 2
- 3
- 4
- 5
- 6
在D盘下生成了test.txt文件,并写入内容:
{"age":23,"id":1,"name":"张三","sex":"男"}
- 1
void writeJSONString(Writer writer, Object object, SerializerFeature... features);
传入的参数还可以是一个Writer对象:
public static void main(String[] args) throws IOException {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
Writer writer = new FileWriter("D:\\test.txt");
JSON.writeJSONString(writer, user);
}
- 1
- 2
- 3
- 4
- 5
同样在D盘下生成了test.txt文件,并写入内容:
{"age":23,"id":1,"name":"张三","sex":"男"}
- 1
四、@JSONField注解(命名重塑)
package com.alibaba.fastjson.annotation;
public @interface JSONField {
//配置序列化和反序列化的顺序,1.1.42版本之后才支持
int ordinal() default 0;
//指定字段的名称
String name() default "";
//指定字段的格式,对日期格式有用
String format() default "";
//是否序列化
boolean serialize() default true;
//是否反序列化
boolean deserialize() default true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
注:若属性是私有的,必须要有set()方法,否则无法反序列化。
@JSONField注解用法很简单,可以配置在getter()、setter()、或者属性字段上。
@Data
@ToString
public class User implements Serializable {
private Integer id;
@JSONField(name="userName")
private String name;
private String sex;
private Integer age;
@JSONField(name="userSex")
public String getSex() {
return sex;
}
@JSONField(name="userSex")
public void setSex(String sex) {
this.sex = sex;
}
@JSONField(name="userAge")
public String getAge() {
return age;
}
@JSONField(name="userAge")
public void setAge(Integer age) {
this.age = age;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
测试并输出结果:
public static void main(String[] args) {
String userJsonStr = "{'userAge':23,'id':1,'userName':'张三','userSex':'男'}";
User user = JSON.parseObject(userJsonStr, User.class);
System.out.println(user);
}
- 1
- 2
- 3
- 4
- 5
User{id=1,name=张三,sex=男,age=23}
- 1
这个方法的最大好处便是用来对接奇奇怪怪的文档,有时候我们需要调用第三方的接口,但是这个接口返回的值可能是不符合命名规范的,那我们这边就需要定义一个实体类去接收它(Map虽然也行,但是也不规范)。
这个时候我们定义的实体的属性名就得按照返回的字段名来命名,这对强迫症程序员来说是致命打击,这个时候@JSONField
的用处就来了,我们简单看个例子,有个车牌信息实体的返回字段是这样的:
{"PLATEID" : 01, "PLATE": '闽A6666D', "IMAGEURL":'http://...'}
- 1
我们可以看到返回的字段全部不满足小驼峰规则,我们定义的实体类可不能这样,借助@JSONField的写法如下:
@Data
@ToString
public class PlateInfo {
/**
* 车牌ID
*/
@JSONField(name="PLATEID")
private Integer plateId;
/**
* 车牌号
*/
@JSONField(name="PLATE")
private String plate;
/**
* 图片URL
*/
@JSONField(name="IMAGEURL")
private Integer imageUrl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
测试下是否能够成功接收结果:
public static void main(Stirng[] args) {
String plateJsonStr = "{'PLATEID':01,'PLATE':'闽A6666D','IMAGEURL':'http://...'}";
PlateInfo plateInfo = JSON.parseObject(plateJsonStr, PlateInfo.class);
System.out.println(plateInfo);
}
- 1
- 2
- 3
- 4
- 5
PlateInfo(plateId=1,plate=闽A6666D,imageUrl=http://...)
- 1
可以看到我们已经成功接收到结果了,而且实体类的命名也符合规范,一举两得。
- format属性:格式化日期
我们也可以使用该注解来将我们的日期格式化成我们想要的样子。
@JSONField(format="yyyy-MM-dd HH:mm:ss")
private Date birthday;
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).birthday(new Date()).build();
System.out.println(JSON.toJSONString(user));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
{"age":23,"birthday":"2023-02-17 14:03:48","id":1,"name":"张三","sex":"男"}
- 1
- serialize属性:控制序列化
- deserialize属性:控制反序列化
在序列化或反序列化的时候我们可以指定字段不序列化,这个有点像Java流中的transient
修饰。FastJson中也可以实现相似的功能:
@JSONField(serialize=false,deserialize=false)
private Date birthday;
public static void main(String[] args) {
String userJsonStr = "{\"age\":23,\"birthday\":\"2023-02-17 02:05:29\",\"id\":1,\"name\":\"张三\",\"sex\":\"男\"}";
User user = JSON.parseObject(userJsonStr, User.class);
System.out.println(user);
System.out.println("===========================");
User user1 = User.builder().id(1).name("张三").sex("男").age(23).birthday(new Date()).build();
System.out.println(JSON.toJSONString(user1));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
User(id=1, name=张三, sex=男, age=23, birthday=null)
===========================
{"age":23,"id":1,"name":"张三","sex":"男"}
- 1
- 2
- 3
但是反序列化有个缺点就是,虽然值是空的,但是属性名还在~
- ordinal属性:指定字段的顺序
@Data
public class User implements Serializable {
@JSONField(ordinal = 2)
private Integer id;
@JSONField(ordinal = 1)
private String name;
@JSONField(ordinal = 4)
private String sex;
@JSONField(ordinal = 3)
private Integer age;
}
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
{"name":"张三","id":1,"age":23,"sex":"男"}
- 1
通过接收结果可以看到属性字段按照我们规定的顺序所排列,用处可以在于我们返回字段给前端过多的时候,将有用的字段优先排列在前面,可以更好的取值,而不用一层一层的查找需要的字段。
- serializeUsing属性:指定属性的序列化类
万物皆可定制,序列化也不例外~我们可以使用serializeUsing指定属性的序列化类。
@Data
public class User implements Serializable {
private Integer id;
private String name;
private String sex;
@JSONFiled(serializeUsing = ModelValueSerializer.class)
private Integer age;
}
/**
* 自定义序列化规则
*/
class ModelValueSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
String value = String.valueOf(object);
String text = value + "岁";
serializer.write(text);
}
}
/**
* 测试类
*/
public static void main(String[] args) {
User user = User.builder().id(1).name("张三").sex("男").age(23).build();
System.out.println(JSON.toJSONString(user));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
{"name":"张三","id":1,"age":"23岁","sex":"男"}
- 1
通过这种方式我们针对age这个属性进行了处理,给指定字段加上了单位。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)