fastjson 使用@JSONType可以实现定制序列化

本文主要详细介绍一下FastJson使用@JSONField、@JSONType、SerializeFilter进行序列化。之前了解的序列化都是非定制化的,本文介绍的fastjson可以按需求进行定制化输出。
  本文使用的fastjson版本为1.2.47

FastJson使用@JSONField、@JSONType、SerializeFilter进行序列化时,强调所有的操作(注解)都是在序列化和反序列化的时候起左右(并且该对象也参与其中),其它的时候不起作用(比如对象.get或.set时候没作用)

1.@JSONField

1.1@JSONField注解代码演示

这个注解可以设置的参数有:ordinal,name,format,serialize,deserialize,jsonDirect等等,后面的不常用啊
对象AAAaaa类:

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class AAAaaa {

@JSONField(name = "userName", ordinal = 2)
private String name;
private Integer age;
private String address;
@JSONField(name = "userWork", ordinal = 1, serialize = false)
private String work;
@JSONField(name = "userSchool", ordinal = 4, deserialize = false)
private String school;
@JSONField(name = "json", ordinal = 4, jsonDirect = true)
private String studentjson;
//yyyy年MM月dd日 HH时mm分ss秒
@JSONField(ordinal = 3, name = "time", format = "yyyy-MM-dd HH:mm:ss")
private Date createtime;

public String getName() {
return name;
}

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

@JSONField(name = "userAge")
public Integer getAge() {
return age;
}

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

public String getAddress() {
return address;
}

@JSONField(name = "userAddress")
public void setAddress(String address) {
this.address = address;
}

public String getWork() {
return work;
}

public void setWork(String work) {
this.work = work;
}

public String getSchool() {
return school;
}

public void setSchool(String school) {
this.school = school;
}

public String getStudentjson() {
return studentjson;
}

public void setStudentjson(String studentjson) {
this.studentjson = studentjson;
}

public Date getCreatetime() {
return createtime;
}

public void setCreatetime(Date createtime) {
this.createtime = createtime;
}

public AAAaaa() {
}

public AAAaaa(String name, Integer age, String address, String work, String school, String studentjson, Date createtime) {
this.name = name;
this.age = age;
this.address = address;
this.work = work;
this.school = school;
this.studentjson = studentjson;
this.createtime = createtime;
}

@Override
public String toString() {
return "AAAaaa{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", work='" + work + '\'' +
", school='" + school + '\'' +
", studentjson='" + studentjson + '\'' +
", createtime=" + createtime +
'}';
}
}

 

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestDemo {
public static void main(String[] args) {
AAAaaa aa=new AAAaaa("xiaoming",20,"北京","英语老师","北京小学","[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]",new Date());
System.out.println(aa);
String s = JSONObject.toJSONString(aa);
//测试序列化
System.out.println(s);
//跟AAAaaa这个对象无关,所以跟@JSONField注解无关
System.out.println(JSONObject.parseObject(s));
//测试反序列化
System.out.println(JSONObject.parseObject(s,AAAaaa.class));
}
}

 

测试结果

1
2
3
4
AAAaaa{name='xiaoming', age=20, address='北京', work='英语老师', school='北京小学', studentjson='[{"studentName":"lily","studentAge":12},{"studentName":"lucy","studentAge":15}]', createtime=Tue Sep 03 17:19:12 CST 2019}
{"address":"北京","userAge":20,"userName":"xiaoming","time":"2019-09-03 17:19:12","json":[{"studentName":"lily","studentAge":12},{"studentName":"lucy","studentAge":15}],"userSchool":"北京小学"}
{"time":"2019-09-03 17:19:12","json":[{"studentName":"lily","studentAge":12},{"studentName":"lucy","studentAge":15}],"address":"北京","userSchool":"北京小学","userName":"xiaoming","userAge":20}
AAAaaa{name='xiaoming', age=null, address='null', work='null', school='null', studentjson='[{"studentName":"lily","studentAge":12},{"studentName":"lucy","studentAge":15}]', createtime=Tue Sep 03 17:19:12 CST 2019}

 

1.2@JSONField注解详细讲解

1)ordinal
这个值的设置,可以使对象的属性按这个顺序来输出,默认值是0,要是都不设置,那就按属性名称的字母顺序来输出(数字小的或字母在前的先输出)
2)name
直接把原来的属性名称代码,给替换成别名
3)format
这个针对日期属性,至于他的值,你可以随意设置格式化格式,前提是复合那个SimpleDateFormat这个类的格式化时间的格式就好,估计是通用的
4)serialize
序列化,默认值是true,都是序列化的,我在model里面设置了个false,然后可以看到,在输出json字符串中,这个属性对应的key和value都不见啦。就是这么个作用
5)deserialize
这个反序列化,默认值也是true,默认都是需要反序列化的,我对name属性设置是false,在字符串转对象对时候,发现对象对name属性是null啦。就是这么个作用。
6)jsonDirect
这个说是,如果对象对某个属性的值是json字符串的话,就不要在做处理啦,直接就是json。

@JSONField注解可以作用在Field字段上也可以作用在setter和getter方法上,当作用在setter方法上时,就相当于根据name到json中寻找对应的值,并调用该setter对象赋值。当作用在getter上时,在bean转换为json时,其key值为name定义的值。

2.@JSONType

@JSONType(naming = PropertyNamingStrategy.PascalCase) 大驼峰命名
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)

可以多个属性并列放@JSONType(orders = {“name”,”work”,”address”},includes={“name”,”work”,”address”})

1
2
3
@JSONType(orders = {"z","a","b","c","d"})        相当于ordinal  
@JSONType(includes={"name","work","address"})  相当于serialize(参与序列化的有name,work,address)
@JSONType(ignores={"name","work","address"})   不参与序列化的有name,work,address

 

3.SerializeFilter

3.1SerializeFilter属性使用

1)在代码中使用

1
2
3
4
5
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";    //把AAAaaa类中format = "yyyy-MM-dd HH:mm:ss"去掉
AAAaaa aa = new AAAaaa(null, 20, "北京", "英语老师", "北京小学", "[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]", new Date());
String s = JSONObject.toJSONString(aa, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue);
//测试序列化
System.out.println(s);

 

测试结果

1
{"address":"北京","userAge":20,"userName":null,"time":"2019-09-04","json":[{"studentName":"lily","studentAge":12},{"studentName":"lucy","studentAge":15}],"userSchool":"北京小学"}

 

2)在@JSONField注解中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AAAaaa {

@JSONType(serialzeFeatures = {SerializerFeature.WriteNullStringAsEmpty,SerializerFeature.WriteMapNullValue})
private String name;
private Integer age;
private String address;
private String work;
private String school;
private String studentjson;
private Date createtime;

......
}

 

3)在@JSONType注解中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
@JSONType(serialzeFeatures = {SerializerFeature.WriteNullStringAsEmpty,SerializerFeature.WriteMapNullValue})
public class AAAaaa {

private String name;
private Integer age;
private String address;
private String work;
private String school;
private String studentjson;
private Date createtime;

......
}

 

3.2SerializeFilter属性列表

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package com.alibaba.fastjson.serializer;

public enum SerializerFeature {
QuoteFieldNames,//输出key时是否使用双引号,默认为true
/**
*
*/
UseSingleQuotes,//使用单引号而不是双引号,默认为false
/**
*
*/
WriteMapNullValue,//是否输出值为null的字段,默认为false
/**
* 1.目前版本的fastjon默认对enum对象使用WriteEnumUsingName属性,因此会将enum值序列化为其Name。
* 2.使用WriteEnumUsingToString方法可以序列化时将Enum转换为toString()的返回值;
* 同时override toString函数能够将enum值输出需要的形式。但是这样做会带来一个问题,对应的反序列化使用的Enum的静态方法
* valueof可能无法识别自行生成的toString(),导致反序列化出错。
* 3.如果将节省enum序列化后的大小,可以将enum序列化其ordinal值,保存为int类型。
* fastJson在反序列化时,如果值为int,则能够使用ordinal值匹配,找到合适的对象。
* fastjson要将enum序列化为ordinal只需要禁止WriteEnumUsingName feature。
* 首先根据默认的features排除WriteEnumUsingName,然后使用新的features序列化即可。
* int features=SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteEnumUsingName, false)
* JSON.toJSONString(obj,features,SerializerFeature.EMPTY);
*/
WriteEnumUsingToString,//用枚举toString()值输出

WriteEnumUsingName,//用枚举name()输出
/**
*
*/
UseISO8601DateFormat,//Date使用ISO8601格式输出,默认为false
/**
*
*/
WriteNullListAsEmpty,//List字段如果为null,输出为[],而非null,默认为false
/**
*
*/
WriteNullStringAsEmpty,//字符类型字段如果为null,输出为"",而非null,默认为false
/**
*
*/
WriteNullNumberAsZero,//数值字段如果为null,输出为0,而非null(包括Integer类型,如果为null,输出为0),默认为false
/**
*
*/
WriteNullBooleanAsFalse,//Boolean字段如果为null,输出为false,而非null,默认为false
/**
*
*/
SkipTransientField,//如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
/**
*
*/
SortField,//按字段名称排序后输出。默认为false
/**
*
*/

/** @deprecated弃用 */
@Deprecated
WriteTabAsSpecial,//把\t做转义输出,默认为false
/**
*
*/
PrettyFormat,//结果是否格式化,默认为false
/**
*
*/
WriteClassName,//序列化时写入类型信息,默认为false。反序列化是需用到
/**
* 对于值相同的键,不使用引用表达
* 不使用类似于下面的方式来输出:
* {"$ref":"$"} 引用根对象
* {"$ref":"@"} 引用自己
* {"$ref":".."} 引用父对象
* {"$ref":"../.."} 引用父对象的父对象
* {"$ref":"$.members[0].reportTo"} 基于路径的引用
*/
DisableCircularReferenceDetect,//消除对同一对象循环引用的问题,默认为false
/**
*
*/
WriteSlashAsSpecial,//对斜杠'/'进行转义
/**
*
*/
BrowserCompatible,//将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
/**
*
*/
WriteDateUseDateFormat,//全局修改日期格式,默认为false,格式为yyyy-MM-dd HH:mm:ss
/**
*
*/
NotWriteRootClassName,
/**
*
*/

/** @deprecated */
DisableCheckSpecialChar,//一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false
/**
* 按["field1",field2,field3,"field4","field5","field6"]这样的格式来输出bean
*/
BeanToArray,//将对象转为array输出
/**
*
*/
WriteNonStringKeyAsString,//把所有的键都作为String
/**
*
*/
NotWriteDefaultValue,
/**
*
*/
BrowserSecure,
/**
*
*/
IgnoreNonFieldGetter,//忽略没有getter的字段
/**
*
*/
WriteNonStringValueAsString,
/**
*
*/
IgnoreErrorGetter,
/**
*
*/
WriteBigDecimalAsPlain,
/**
*
*/
MapSortField;
/**
*
*/

public final int mask = 1 << this.ordinal();
public static final SerializerFeature[] EMPTY = new SerializerFeature[0];
public static final int WRITE_MAP_NULL_FEATURES = WriteMapNullValue.getMask() | WriteNullBooleanAsFalse.getMask() | WriteNullListAsEmpty.getMask() | WriteNullNumberAsZero.getMask() | WriteNullStringAsEmpty.getMask();

private SerializerFeature() {
}

public final int getMask() {
return this.mask;
}

/**
* 判断features所代表的特性集合中是否包含有feature特性
* 这里巧妙的使用了一个掩码(mask)来计算,mask是通过对1进行移位得到的
* 因为每一个SerializerFeature在枚举中的序数是固定的,所以mask的
* 值就是像下面的二进制形式:
* 00000000000000000000000000000001
* 00000000000000000000000000000010
* 00000000000000000000000000000100
* 00000000000000000000000000001000
* ......
* 10000000000000000000000000000000
* 所以通过&运算很容易就判断出features中有没有feature。例如:
* feature是WriteMapNullValue(0000000000000000000000000000100),
* features是15(0000000000000000000000000001111),很容易知道features
* 中包含有feature。(可通过SerializerFeature数组计算features,下面提供的
* of方法就可以计算features的值(SerializerFeature数组的掩码(mask)))
* @param features
* @param feature
* @return
*/
public static boolean isEnabled(int features, SerializerFeature feature) {
return (features & feature.mask) != 0;
}

/**
* 检查features或者fieaturesB是否包含feature
* 和上一个方法一样
* @param features
* @param fieaturesB
* @param feature
* @return
*/
public static boolean isEnabled(int features, int fieaturesB, SerializerFeature feature) {
int mask = feature.mask;
return (features & mask) != 0 || (fieaturesB & mask) != 0;
}

/**
* 为features增加feature特性,或者剔除feature特性
* 当state为true时为features增加feature特性
* 当state为false时为features剔除feature特性
* @param features
* @param feature
* @param state
* @return
*/
public static int config(int features, SerializerFeature feature, boolean state) {
if(state) {
features |= feature.mask;
} else {
features &= ~feature.mask;
}

return features;
}

/**
* 计算SerializerFeature数组的掩码(mask)
* 通过|运算把features中的特性叠加起来
* @param features
* @return
*/
public static int of(SerializerFeature[] features) {
if(features == null) {
return 0;
} else {
int value = 0;
SerializerFeature[] var2 = features;
int var3 = features.length;

for(int var4 = 0; var4 < var3; ++var4) {
SerializerFeature feature = var2[var4];
value |= feature.mask;
}

return value;
}
}
}

相关博客链接: https://blog.csdn.net/liupeifeng3514/article/details/79166566

posted @   Mikey-  阅读(2982)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示