fastjson最佳实践小结

fastjson小结

1、遵循javabean 规范和json规范

正确实现setter、getter,用别名就加annotation( @JSONField(name = “user_name”))

2、使用正常的key

尽量不要使用数字等字符开头的key,尽量使用符合java 的class 或property命名规范的key。例如不要使用a.1这种key

3、尽量使用标准的日期格式

序列化和反序列化里都是用相同的dataPattern格式

4、尽量不要用自定义序列化和反序列化

除非万不得已,优先考虑使用注解过滤、别名等方式,甚至可以考虑新建一个vo类来组装实际需要的属性。使用自定义序列化千万要小心,改变了pojo–jsonstring的自然对应关系,不利于代码阅读和排查问题;反序列化可能会出错。

5、尽量避免循环引用
6、注意编码和不可见字符

对于inputstream、outputstream的处理,有时候会报一些奇怪的错误,日志的json字符串正常,但就是报错。这可能就是编码问题,也有可能是utf-8文件的bom头,这些潜在的问题可能在二进制数据转文本的时候,因为一些不可见字符无法显示,导致日志看起来只有正常字符而是正确的,问题很难排查。


使用实例:
  • 1、序列化一个对象成json字符串
1
2
3
4
5
6
User user= new User();
user.setName("xiaoMing");
user.setAge(3);
String jsonString = JSON.toJSONString(user);
System.out.println(jsonString);
//{"age":3,"name":"xiaoMing"}
  • 2、反序列化一个json串为java对象
1
2
3
4
5
6
7
8
9
String jsonString = "{\"age\":3,\"birthdate\":1496738822842,\"name\":\"校长\",\"old\":true,\"salary\":123456789.0123}";
User u = JSON.parseObject(jsonString ,User.class);
System.out.println(u.getName());
// 输出 校长

String jsonStringArray = "[{\"age\":3,\"birthdate\":1496738822842,\"name\":\"校长\",\"old\":true,\"salary\":123456789.0123}]";
List<User> userList = JSON.parseArray(jsonStringArray, User.class);
System.out.println(userList.size());
// 输出 1
  • 3、日志输出格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class Model {
@JSONField(format = "MMM dd, yyyy h:mm:ss aa")
private java.util.Date date;

public java.util.Date getDate() {
return date;
}

public void setDate(java.util.Date date) {
this.date = date;
}

@JSONField(format = "MMM-dd-yyyy h:mm:ss aa")
public java.sql.Date date2;
}
  • 4、特性设置
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
QuoteFieldNames, //key使用引号
UseSingleQuotes, //使用单引号
WriteMapNullValue, //输出Map的null值
WriteEnumUsingToString, //枚举属性输出toString的结果
WriteEnumUsingName, //枚举数据输出name
UseISO8601DateFormat, //使用日期格式
WriteNullListAsEmpty, //List为空则输出[]
WriteNullStringAsEmpty, //String为空则输出””
WriteNullNumberAsZero, //Number类型为空则输出0
WriteNullBooleanAsFalse, //Boolean类型为空则输出false
SkipTransientField,
SortField, //排序字段
WriteTabAsSpecial,
PrettyFormat, // 格式化JSON缩进
WriteClassName, // 输出类名
DisableCircularReferenceDetect, // 禁止循环引用
WriteSlashAsSpecial, // 对斜杠’/’进行转义
BrowserCompatible,
WriteDateUseDateFormat, // 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
NotWriteRootClassName,
DisableCheckSpecialChar,
BeanToArray,
WriteNonStringKeyAsString,
NotWriteDefaultValue,
BrowserSecure,
IgnoreNonFieldGetter,
WriteNonStringValueAsString,
IgnoreErrorGetter,
WriteBigDecimalAsPlain,
MapSortField
使用示例如下(可以参见此处):
Word word = new Word();
word.setA("a");
word.setB(2);
word.setC(true);
word.setD("d");
word.setE("");
word.setF(null);
word.setDate(new Date());

System.out.println(JSON.toJSONString(word));
System.out.println(JSON.toJSONString(word, SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteNullListAsEmpty));
  • 5、注解使用
    1) JSONField
    可以配置在属性(setter、getter)和字段(必须是public field)上。

    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
    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;
    }


    @JSONField(name="ID")
    public int getId() {return id;}

    // 配置date序列化和反序列使用yyyyMMdd日期格式
    @JSONField(format="yyyyMMdd")
    public Date date1;

    // 不序列化
    @JSONField(serialize=false)
    public Date date2;

    // 不反序列化
    @JSONField(deserialize=false)
    public Date date3;

    // 按ordinal排序
    @JSONField(ordinal = 2)
    private int f1;

    @JSONField(ordinal = 1)
    private int f2;
  • 6、object 转map

1
2
3
4
5
6
7
8
9
10
11
12
13
Map<String, Object> paramsMap = JSON.parseObject(JSON.toJSONString(request));
User u = new User();
u.setName("xiaoMing");

Map<String, Object> paramsMap1 = (Map<String, Object>) JSON.toJSON(u);
System.out.println(paramsMap1.get("name")); //xiaoMing
System.out.println(paramsMap1.get("age"));//null
System.out.println(paramsMap1.containsKey("age"));//true

Map<String, Object> paramsMap = JSON.parseObject(JSON.toJSONString(u));
System.out.println(paramsMap.get("name"));//xiaoMing
System.out.println(paramsMap.get("age"));//null
System.out.println(paramsMap.containsKey("age"));//false

使用(Map<String, Object>) JSON.toJSON(u); 会把空值设置为“null” 字符串,导致异常。所以在转map时,建议使用JSON.parseObject(JSON.toJSONString(u));

  • 7、使用typereference处理反序列化泛型问题

jsonobject的使用

jsonobject是json字符串和pojo对象转换过程中的中间表达类型,==++实现了map接口++==。 可以看作是一个模拟json对象键值对再加上多层嵌套的数据集合,对象的每一个基本属性是map里的一个key-value,一个非基本类型属性是一个嵌套的jsonobject对象(key是属性名称,value是表示这个属性值的对象的jsonobject)。
对于jsonstring 转 pojo 或者pojo转jsonstring,尽量使用直接转的方式,而不是先转成jsonobject过渡的方式。对于fastjson,由于性能优化的考虑,这来两个执行的代码是不一样的,可能导致不一样的结果。

1
2
3
4
5
6
7
8
9
String jsonstring = "{\"a\":12}";

// 不推荐这种方式
// 除非这里需要对jsonObject做一些简单处理
JSONObject jsonObject = JSON.parseObject(jsonstring);
A a = jsonObject.toJavaObject(A.class);

// 推荐方式
A a = JSON.parseObject(jsonstring, A.class);
0%