常用的序列化工具最佳实践

作为java开发者,我们常用的序列化方式主要有3种:jackson 、fastJson(fastJson2)、gson。但在使用场景上,他们有不同的偏向。

使用建议

a.Jackson的扩展性较强,且SpringBoot默认是使用Jackson作为JSON数据格式处理的类库。因此关于接口返回的处理,仍可使用jackson处理。

b.Gson的功能较为全面,且支持具有深度继承层次结构的复杂对象转换。如果只是功能要求,没有特别严格的性能要求,可以使用google的Gson;

c.fastJson的速度相对较快,可在高并发场景中使用。但在复杂类型的Bean转换Json上(如泛型嵌套)可能会出现一些问题,且与升级版本fastJson2在序列化格式上并不完全兼容。另外自身被爆安全漏洞较多

注意事项

1.不要使用hutool封装的JsonUtil工具,性能较差;

2.同一个业务逻辑中,最好使用同一种序列化方式。不要混用json序列化的方式。

如下代码出现fastJson和Gson混用,不建议使用:

JSONObject.parseObject(new Gson().toJson(jsonObject),UserDTO.class)

3.日期格式的处理要谨慎。不同序列化方式,Date类型的字段序列化的格式不一样,fastJson和jackson都是序列化成为时间戳,但gson是日期格式。因此针对跨服务场景下的日期字段,需在约定统一格式进行处理。

比如针对全局的springMVC处理,可以做如下配置,则所有接口的Date类型字段都会按照统一格式返回。

spring.jackson.date-format= yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone= GMT+8

4.非驼峰书写格式字段处理要注意。

在项目定义的java bean 中,针对属性是首字母有大写的特殊情况,不同序列化方式的处理不同。最好加上@JsonProperty 注解或Fastjson 的@JSONField注解。

比如针对如下的bean  USERPwd和UserAccount 都是首字母大写:

@Data
public class UserDTO {
 
    private String userName;
 
//    @JsonProperty(value ="USERPwd")
    private String USERPwd;
 
 //    @JsonProperty(value ="UserAccount")
    private String UserAccount;
 
    private String eName;
    private Integer age;
    private Date time;
}

在没有任何注解的情况下,分别使用jackson、fastJson、gson进行序列化,区别如下:

jackson:          {"userName":"test","age":20,"ename":"hello","userpwd":"abc123","UserAccount":"Liu8888"}

fastJson:         {"age":20,"eName":"hello","uSERPwd":"abc123","userAccount":"Liu8888","userName":"test"}

fastJson2:       {"EName":"hello","USERPwd":"abc123","age":20,"userAccount":"Liu8888","userName":"test"}

gson:              {"userName":"test","USERPwd":"abc123","UserAccount":"Liu8888","eName":"hello","age":20}

5.注意泛型类型擦除问题

以上述的UserDTO 为例,假设对List<UserDTO> 一个集合信息做序列化后,如果直接进行反序列化,则会因为泛型信息缺失,导致反序列化后的集合元素并非UserDTO类型(fastJson是JSONObject,gson对应的是LinkedTreeMap).

此时需借助如下方式处理:fastJson采用TypeReference 处理;gson采用TypeToken 方式处理。

6.JDK8的LocalDateTime类型转换时要注意

Jackson默认的ObjectMapper不支持,需要加入如下配置才可以:

objectMapper.registerModule(new JavaTimeModule());

附录:

这里给出了基于Gson的工具类封装,大家可以直接使用:

public class JsonUtil {

    /**
     * 定义全局GsonBuilder对象
     */
    private static final Gson gson =new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

    private JsonUtil(){

    }

    public static Gson getInstance(){
        return gson;
    }

    public static String toJson(Object src) {
        return gson.toJson(src);
    }

    public static String toJson(Object src, Type typeOfSrc) {
        return gson.toJson(src,typeOfSrc);
    }

    /**
     * 根据class类型解析json
     * @param json
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T fromJson(String json, Class<T> classOfT) {
        return gson.fromJson(json,classOfT);
    }

    /**
     * 根据type解析json
     * @param json
     * @param typeOfT
     * @param <T>
     * @return
     */
    public static <T> T fromJson(String json, Type typeOfT) {
        return gson.fromJson(json,typeOfT);
    }

    /**
     * json 转成 特定的cls的list
     * @param json
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> List<T> fromJsonList(String json, Class<T> classOfT) {
//        return gson.fromJson(json,new TypeToken<List<T>>() {}.getType());
        Type typeOfT = TypeToken.getParameterized(List.class, classOfT).getType();
        return gson.fromJson(json, typeOfT);
    }


    /**
     * json 转成 特定的 rawClass<classOfT> 的Object
     *
     * @param json
     * @param classOfT
     * @param argClassOfT
     * @return
     */
    public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {
        Type type = new GsonUtil.ParameterizedType4ReturnT(classOfT, new Class[]{argClassOfT});
        return gson.fromJson(json, type);
    }

    public static class ParameterizedType4ReturnT implements ParameterizedType {
        private final Class raw;
        private final Type[] args;
        public ParameterizedType4ReturnT(Class raw, Type[] args) {
            this.raw = raw;
            this.args = args != null ? args : new Type[0];
        }
        @Override
        public Type[] getActualTypeArguments() {
            return args;
        }
        @Override
        public Type getRawType() {
            return raw;
        }
        @Override
        public Type getOwnerType() {return null;}
    }

}

注意:GsonBuilder这里指定了统一的日期格式为:"yyyy-MM-dd HH:mm:ss"。如果大家在项目中需要使用其他日期格式,请替换此格式即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值