工具类🔧-Fastjson进阶使用

fastjson用于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
主要就以下几点做个介绍

  • SerializerFeature特性的使用
  • JSONField与JSONType注解的使用
  • SerializeFilter
  • 泛型反序列化
  • fastjson各种概念

简单使用

  • 通过maven引入相应的json包

    1
    2
    3
    4
    5
    6
    7
    <dependencies>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.58</version>
    </dependency>
    </dependencies>
  • 定义一个需要转换所实体类User,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.ohaotian.feifz.style.study.utils.fastjson;

    /**
    * @author feifz
    * @version 1.0.0
    * @Description 研究fastjson用到的对象
    * @createTime 2019年06月10日 16:36:00
    */
    import com.alibaba.fastjson.annotation.JSONField;
    import lombok.Data;
    import java.util.Date;
    @Data
    public class User {
    private Long id;
    private String name;
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    }
  • 写个简单的测试类用于测试fastjson的序列化与反序列化,代码如下:

    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
    36
    package com.ohaotian.feifz.style.study.utils.fastjson;

    /**
    * @author feifz
    * @version 1.0.0
    * @Description fastjson简单使用
    * @createTime 2019年06月10日 16:37:00
    */

    import com.alibaba.fastjson.JSON;

    import java.util.Date;

    public class SimpleTest {

    public static void main(String[] args) {
    serialize();
    deserialize();
    }

    public static void serialize() {
    User user = new User();
    user.setId(11L);
    user.setName("西安");
    user.setCreateTime(new Date());
    String jsonString = JSON.toJSONString(user, true);
    System.out.println(jsonString);
    }

    public static void deserialize() {
    String jsonString = "{\"createTime\":\"2018-08-17 14:38:38\",\"id\":11,\"name\":\"西安\"}";
    User user = JSON.parseObject(jsonString, User.class);
    System.out.println(user.getName());
    System.out.println(user.getCreateTime());
    }
    }

SerializerFeature特性的使用

fastjson通过SerializerFeature对生成的json格式的数据进行一些定制,比如可以输入的格式更好看,使用单引号而非双引号等。例子程序如下:

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
package com.ohaotian.feifz.style.study.utils.fastjson;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.util.Date;

/**
* @author feifz
* @version 1.0.0
* @Description SerializerFeature特性的使用
* @createTime 2019年06月10日 16:40:00
*/
public class SerializerFeatureTest {

public static void main(String[] args) {
User user = new User();
user.setId(11L);
user.setCreateTime(new Date());
String jsonString = JSON.toJSONString(user, SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.UseSingleQuotes);
System.out.println(jsonString);

}

}

输出的结果如下:

1
2
3
4
5
{
'createTime':'2019-06-10 17:25:34',
'id':11,
'name':''
}

SerializerFeature常用属性

名称 含义
QuoteFieldNames 输出key时是否使用双引号,默认为true
UseSingleQuotes 使用单引号而不是双引号,默认为false
WriteMapNullValue 是否输出值为null的字段,默认为false
WriteEnumUsingToString Enum输出name()或者original,默认为false
UseISO8601DateFormat Date使用ISO8601格式输出,默认为false
WriteNullListAsEmpty List字段如果为null,输出为[],而非null
WriteNullStringAsEmpty 字符类型字段如果为null,输出为”“,而非null
WriteNullNumberAsZero 数值字段如果为null,输出为0,而非null
WriteNullBooleanAsFalse Boolean字段如果为null,输出为false,而非null
SkipTransientField 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
SortField 按字段名称排序后输出。默认为false
WriteTabAsSpecial 把\t做转义输出,默认为false不推荐设为true
PrettyFormat 结果是否格式化,默认为false
WriteClassName 序列化时写入类型信息,默认为false。反序列化是需用到
DisableCircularReferenceDetect 消除对同一对象循环引用的问题,默认为false
WriteSlashAsSpecial 对斜杠’/’进行转义
BrowserCompatible 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
WriteDateUseDateFormat 全局修改日期格式,默认为false。
DisableCheckSpecialChar 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false
BeanToArray 将对象转为array输出

JSONField与JSONType注解的使用

注意和@JSONField不同的是,@JSONType是配置在类上的,而@JSONField是配置在字段和方法上的。

JSONField注解的使用

fastjson提供了JSONField对序列化与反序列化进行定制,比如可以指定字段的名称,序列化的顺序。JSONField用于属性,方法方法参数上。JSONField的源码如下:

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
36
37
38
39
40
package com.alibaba.fastjson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
// 配置序列化和反序列化的顺序
int ordinal() default 0;
// 指定字段的名称
String name() default "";
// 指定字段的格式,对日期格式有用
String format() default "";
// 是否序列化
boolean serialize() default true;
// 是否反序列化
boolean deserialize() default true;
//字段级别的SerializerFeature
SerializerFeature[] serialzeFeatures() default {};
//
Feature[] parseFeatures() default {};
//给属性打上标签, 相当于给属性进行了分组
String label() default "";

boolean jsonDirect() default false;

//制定属性的序列化类
Class<?> serializeUsing() default Void.class;
//制定属性的反序列化类
Class<?> deserializeUsing() default Void.class;

String[] alternateNames() default {};

boolean unwrapped() default false;
}

属性

name

通过在注解@JSONField指定属性name可以指定该属性在序列化和反序列化过程中输出的key。可作用于Field上,也可作用于setter和setter方法上。
一、作用Field (相当于get set的总和)
@JSONField作用在Field时,其name不仅定义了输入key的名称,同时也定义了输出的名称。
二、作用在setter和getter方法上
顾名思义,当作用在setter方法上时,就相当于根据name到json中寻找对应的值,并调用该setter对象赋值。
当作用在getter上时,在bean转换为json时,其key值为name定义的值。
示例如下:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.ohaotian.feifz.style.study.utils.fastjson;

/**
* @author feifz
* @version 1.0.0
* @Description JSONField注解 name属性用法
* @createTime 2019年06月11日 14:00:00
*/

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;

public class JsonFieldNameDemo {

@JSONField(name = "jsonName")
private String name;

private String age;

private String email;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
@JSONField(name = "jsonAge")
public String getAge() {
return age;
}

@JSONField(name = "jsonAge")
public void setAge(String age) {
this.age = age;
}

public String getEmail() {
return email;
}
@JSONField(name = "jsonEmail")
public void setEmail(String email) {
this.email = email;
}

@Override
public String toString() {
return "JsonFieldNameDemo [name=" + name + ", age=" + age + ", email="
+ email + "]";
}


public static void main(String[] args) {

JsonFieldNameDemo jsonFieldNameDemo = new JsonFieldNameDemo();
jsonFieldNameDemo.setAge("21岁");
jsonFieldNameDemo.setEmail("111@11.com");
jsonFieldNameDemo.setName("hhh");

System.out.println(JSON.toJSONString(jsonFieldNameDemo));
//输出了:{"jsonName":"hhh","jsonAge":"21岁","email":"111@11.com"}

String json = "{\"email\":\"111@11.com\",\"jsonAge\":\"21岁\",\"jsonName\":\"hhh\"}";
JsonFieldNameDemo jsonTest = JSON.parseObject(json, JsonFieldNameDemo.class);
System.out.println(jsonTest.toString());
}

}

输出结果如下:

1
2
{"email":"111@11.com","jsonAge":"21岁","jsonName":"hhh"}
JsonFieldNameDemo [name=hhh, age=21岁, email=null]

serialize,deserialize

serialize:是否序列化,默认值都为true,指定为false时序列化过程中不序列化该字段。
deserialize:是否反序列化,默认值都为true,指定为false时反序列化过程中不反序列化该字段
示例代码如下:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.ohaotian.feifz.style.study.utils.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;

/**
* @author feifz
* @version 1.0.0
* @Description @JSONField name属性示例
* @createTime 2019年06月11日 14:09:00
*/
public class JsonFieldNameDemo {

private String name;

@JSONField(deserialize = false)
private String age;

@JSONField(serialize = false)
private String email;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

@Override
public String toString() {
return "JsonFieldNameDemo{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", email='" + email + '\'' +
'}';
}

public static void main(String[] args) {
JsonFieldNameDemo jsonFieldNameTest1 = new JsonFieldNameDemo();
jsonFieldNameTest1.setAge("18");
jsonFieldNameTest1.setEmail("123@163.com");
jsonFieldNameTest1.setName("Bob");
System.out.println(JSON.toJSONString(jsonFieldNameTest1));

String json = "{\"age\":\"18\",\"email\":\"123@163.com\",\"name\":\"Bob\"}";
JsonFieldNameDemo jsonFieldNameTest2 = JSON.parseObject(json, JsonFieldNameDemo.class);
System.out.println(jsonFieldNameTest2.toString());

}
}

输出结果如下:

1
2
{"age":"18","name":"Bob"}
JsonFieldNameDemo{name='Bob', age='null', email='123@163.com'}

serializeUsing,deserializeUsing

其中serializeUsing与deserializeUsing可以用于对字段的序列化与反序列化进行定制化。比如我们在User实体上加上个sex属性,类型为boolean。下面分别定义了序列化类与反序列化类。
序列化类代码如下:

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
package com.ohaotian.feifz.style.study.utils.fastjson;

/**
* @author feifz
* @version 1.0.0
* @Description TODO
* @createTime 2019年06月11日 10:23:00
*/

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;

import java.io.IOException;
import java.lang.reflect.Type;

public class SexSerializer implements ObjectSerializer {

@Override
public void write(JSONSerializer serializer,
Object object,
Object fieldName,
Type fieldType,
int features)
throws IOException {
Boolean value = (Boolean) object;
String text = "女";
if (value != null && value == true) {
text = "男";
}
serializer.write(text);
}

}

反序列化类代码如下:

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
36
37
package com.ohaotian.feifz.style.study.utils.fastjson;

/**
* @author feifz
* @version 1.0.0
* @Description TODO
* @createTime 2019年06月11日 10:24:00
*/

import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;

import java.lang.reflect.Type;

public class SexDeserialize implements ObjectDeserializer {

@Override
public <T> T deserialze(DefaultJSONParser parser,
Type type,
Object fieldName) {


String sex = parser.parseObject(String.class);
if ("男".equals(sex)) {
return (T) Boolean.TRUE;
} else {
return (T) Boolean.FALSE;
}
}

@Override
public int getFastMatchToken() {
return JSONToken.UNDEFINED;
}

}

在定义bean对象时在字段sex上加上注解如下:

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
package com.ohaotian.feifz.style.study.utils.fastjson;

/**
* @author feifz
* @version 1.0.0
* @Description 研究fastjson用到的对象
* @createTime 2019年06月10日 16:36:00
*/

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;

import java.util.Date;

@Data
public class User {

private Long id;

private String name;

@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;

@JSONField(serializeUsing = SexSerializer.class, deserializeUsing = SexDeserialize.class)
private Boolean sex;

}

这样在执行下面代码之后就会发现对sex字段的值定制化了

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
36
37
38
package com.ohaotian.feifz.style.study.utils.fastjson;

/**
* @author feifz
* @version 1.0.0
* @Description fastjson简单使用
* @createTime 2019年06月10日 16:37:00
*/

import com.alibaba.fastjson.JSON;

import java.util.Date;

public class SimpleTest {

public static void main(String[] args) {
serialize();
deserialize();
}

public static void serialize() {
User user = new User();
user.setId(11L);
user.setName("西安");
user.setSex(false);
user.setCreateTime(new Date());
String jsonString = JSON.toJSONString(user, true);
System.out.println(jsonString);
}

public static void deserialize() {
String jsonString = "{\"createTime\":\"2018-08-17 14:38:38\",\"id\":11,\"name\":\"西安\",\"sex\":\"男\"}";
User user = JSON.parseObject(jsonString, User.class);
System.out.println(user.getSex());
System.out.println(user.getName());
System.out.println(user.getCreateTime());
}
}

输出的结果如下:

1
2
3
4
5
6
7
8
9
{
"createTime":"2019-06-11 11:20:08",
"id":11,
"name":"西安",
"sex":"女"
}
true
西安
Fri Aug 17 14:38:38 CST 2018

JSONType注解的使用

fastjosn提供了JSONType用于类级别的定制化, JSONType的源码如下:

源码

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.alibaba.fastjson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;

@Retention(RetentionPolicy.RUNTIME)
//需要标注在类上
@Target({ ElementType.TYPE })
public @interface JSONType {

boolean asm() default true;
//这里可以定义输出json的字段顺序
String[] orders() default {};
//包含的字段
String[] includes() default {};
//不包含的字段
String[] ignores() default {};
//类级别的序列化特性定义
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
//按字母顺序进行输出
boolean alphabetic() default true;

Class<?> mappingTo() default Void.class;

Class<?> builder() default Void.class;

String typeName() default "";

String typeKey() default "";

Class<?>[] seeAlso() default{};
//序列化类
Class<?> serializer() default Void.class;
//反序列化类
Class<?> deserializer() default Void.class;

boolean serializeEnumAsJavaBean() default false;

PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;

Class<? extends SerializeFilter>[] serialzeFilters() default {};
}

属性

  • includes
    序列化时,只序列化这些字段
    使用示例:@JSONType(includes = {“name”,”age”})
  • ignores
    序列化时,忽略这些字段
    使用示例:@JSONType(ignores = {“email”})
  • orders
    序列化时,按照指定的顺序输出结果
    使用示例:@JSONType(orders = {“name”,”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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.ohaotian.feifz.style.study.utils.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONType;

/**
* @author feifz
* @version 1.0.0
* @Description @JSONType 注解使用示例
* @createTime 2019年06月11日 14:41:00
*/
@JSONType(includes = {"name","age"},ignores = {"email"},orders = {"name","age"})
public class JsonTypeDemo {

private String name;

private String age;

private String email;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public JsonTypeDemo(String name, String age, String email) {
this.name = name;
this.age = age;
this.email = email;
}

@Override
public String toString() {
return "JsonTypeDemo{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", email='" + email + '\'' +
'}';
}

public static void main(String[] args) {
JsonTypeDemo demo = new JsonTypeDemo("Mary","17","123@163.com");
System.out.println(JSON.toJSONString(demo));

String json = "{\"age\":\"17\",\"email\":\"123@163.com\",\"name\":\"Mary\"}";
JsonTypeDemo jsonTypeDemo = JSON.parseObject(json,JsonTypeDemo.class);
System.out.println(jsonTypeDemo.toString());
}
}

输出结果如下:

1
2
{"name":"Mary","age":"17"}
JsonTypeDemo{name='Mary', age='17', email='123@163.com'}

SerializeFilter

泛型反序列化

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
36
37
38
39
40
41
42
43
44
45
46
```

# fastjson各种概念
* JSON:本身是Abstract,提供了一系统的工具方法方便用户使用的API。

## 序列化相关的概念
* SerializeConfig:内部是个map容器主要功能是配置并记录每种Java类型对应的序列化类。
* SerializeWriter 继承自Java的Writer,其实就是个转为FastJSON而生的StringBuilder,完成高性能的字符串拼接。
* SerializeFilter: 用于对对象的序列化实现各种定制化的需求。
* SerializerFeature:对于对输出的json做各种格式化的需求。
* JSONSerializer:相当于一个序列化组合器,集成了*SerializeConfig, SerializeWriter , SerializeFilter与SerializerFeature。
序列化的入口代码如下,上面提到的各种概念都包含了:
``` java
/**
* @since 1.2.9
* @return
*/
public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

try {
JSONSerializer serializer = new JSONSerializer(out, config);

if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}

if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}

serializer.write(object);

return out.toString();
} finally {
out.close();
}
}

反序列化相关的概念

ParserConfig:内部通过一个map保存各种ObjectDeserializer。
JSONLexer : 与SerializeWriter相对应,用于解析json字符串。
JSONToken:定义了一系统的特殊字符,这些称为token。
ParseProcess :定制反序列化,类似于SerializeFilter。
Feature:用于定制各种反序列化的特性。
DefaultJSONParser:相当于反序列化组合器,集成了ParserConfig,Feature, JSONLexer 与ParseProcess。
反序列化的入口代码如下,上面的概念基本都包含了:

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
36
37
@SuppressWarnings("unchecked")
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor,
int featureValues, Feature... features) {
if (input == null) {
return null;
}

if (features != null) {
for (Feature feature : features) {
featureValues |= feature.mask;
}
}

DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);

if (processor != null) {
if (processor instanceof ExtraTypeProvider) {
parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
}

if (processor instanceof ExtraProcessor) {
parser.getExtraProcessors().add((ExtraProcessor) processor);
}

if (processor instanceof FieldTypeResolver) {
parser.setFieldTypeResolver((FieldTypeResolver) processor);
}
}

T value = (T) parser.parseObject(clazz, null);

parser.handleResovleTask(value);

parser.close();

return (T) value;
}

参考