• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

fastjson2.x 记录那些从1.x升级到2.x踩过的坑

武飞扬头像
reui
帮助1

这篇文章主要记录升级到 fastjson2.x 版本后出现的一些问题 

1. jar 包引入问题

问题描述:从 2.x 版本后,fastjson 貌似开始对代码模块进行了拆分,所以在调整配置的时候,会发现有些类突然没了,其实是需要引入其他的扩展包。

从 2.0.22 版本开始,需要引入下面三个 jar 包

  1.  
    <dependency>
  2.  
    <groupId>com.alibaba.fastjson2</groupId>
  3.  
    <artifactId>fastjson2</artifactId>
  4.  
    </dependency>
  5.  
     
  6.  
    <dependency>
  7.  
    <groupId>com.alibaba.fastjson2</groupId>
  8.  
    <artifactId>fastjson2-extension</artifactId>
  9.  
    </dependency>
  10.  
     
  11.  
    <dependency>
  12.  
    <groupId>com.alibaba.fastjson2</groupId>
  13.  
    <artifactId>fastjson2-extension-spring5</artifactId>
  14.  
    </dependency>

起初的 2.x 版本,只需要引入前两个 jar 包,后面想更新一下新版本,好家伙,又分出来一个 fastjson2-extension-spring5,其实就是将 spring 的一些相关的配置类独立出来了。

学新通

 用的最多应该是 redis 的序列化类,还有 http 的消息解析器。

2. 自定义序列化 ObjectWriter 类的 writeXXX 方法问题

问题描述:1.x 版本中 SerializeWriter 的 write 方法,在 2.x 版本中 ObjectWriter 并没有提供,反而提供很多不同的 writeXXX 方法,匹配不同的返回类型,如 writeString 方法,就会返回一个字符类型。

之前系统使用 1.2.83 版本,写了一个 LocalDateTime 序列化为时间戳毫秒数的自定义序列化类,使用的是 SerializeWriter 的 write 方法。

  1.  
    public class DateJsonSerializer implements ObjectSerializer {
  2.  
     
  3.  
    @Override
  4.  
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
  5.  
    SerializeWriter out = serializer.getWriter();
  6.  
    if (object == null) {
  7.  
    serializer.getWriter().writeNull();
  8.  
    return;
  9.  
    }
  10.  
    if (object instanceof LocalDateTime) {
  11.  
    LocalDateTime localDateTime = (LocalDateTime) object;
  12.  
    out.write(localDateTime.toInstant(ZoneOffset.of(" 8")).toEpochMilli() "");
  13.  
    }
  14.  
    }
  15.  
    }
学新通

控制器测试代码如下

  1.  
    @GetMapping("/test")
  2.  
    public DemoTestResponse test() {
  3.  
     
  4.  
    DemoTestResponse response = new DemoTestResponse();
  5.  
     
  6.  
    response.setDateTime(LocalDateTime.now());
  7.  
     
  8.  
    return response;
  9.  
    }

返回对象如下

  1.  
    @Data
  2.  
    public class DemoTestResponse {
  3.  
     
  4.  
    @JSONField(name = "date_time", serializeUsing = DateJsonSerializer.class)
  5.  
    private LocalDateTime dateTime;
  6.  
     
  7.  
    }

postman 运行后结果如下,可以看到自定义序列化生效了,并且返回了数字型的时间戳。

学新通

 升级到 2.x 版本后,重写了这个自定义序列化类,如下

  1.  
    public class DateJsonSerializer implements ObjectWriter {
  2.  
     
  3.  
    @Override
  4.  
    public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
  5.  
    if (object == null) {
  6.  
    jsonWriter.writeNull();
  7.  
    return;
  8.  
    }
  9.  
     
  10.  
    if (object instanceof LocalDateTime) {
  11.  
    LocalDateTime localDateTime = (LocalDateTime) object;
  12.  
    jsonWriter.writeString(localDateTime.toInstant(ZoneOffset.of(" 8")).toEpochMilli() "");
  13.  
    }
  14.  
    }
  15.  
    }
学新通

这里使用了 JSONWriter 的 writeString 方法,这也是问题所在,还是运行上面的方法,返回结果如下,变为了一个字符串了。

学新通

因为当时没留意,所以就以为 writeString 的意思是参数为字符串类型就用了。其实 JSONWriter 类提供了很多的 writeXXX 方法。学新通

 这里我们应该使用 writeMillis 方法,如下图

  1.  
    @Override
  2.  
    public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
  3.  
    if (object == null) {
  4.  
    jsonWriter.writeNull();
  5.  
    return;
  6.  
    }
  7.  
     
  8.  
    if (object instanceof LocalDateTime) {
  9.  
    LocalDateTime localDateTime = (LocalDateTime) object;
  10.  
    jsonWriter.writeMillis(localDateTime.toInstant(ZoneOffset.of(" 8")).toEpochMilli());
  11.  
    }
  12.  
    }

运行结果如下,问题解决。 

学新通

3. JSONField 注解智能匹配失效

问题描述:在使用 1.x 版本时,字段使用的@JSONField(name = "openid"),前端传过来的字段名为 open_id,接口能正常运行。但是升级到 2.x 版本时,就为空值。

这是一个隐藏很深的bug,估计是当时开发接口的时候也没有注意,接口已能够正常运行。但是升级到 2.x 版本时,就出问题了。

其实这得益于 fastjson 的智能匹配,忽略了大小写和下划线,依然将 json 映射成功。但是在 2.x 版本后,貌似智能匹配并没有默认开启,所以就出现映射不成功的情况。

笔者尝试使用 开启智能匹配,但是没有成功,原因未明,先记录下来,后面有时间去看一下源码。从官网的 Issues 来看,也有不少这种序列化和反序列化的问题,先版本的更新也针对这种情况的比较多。

请求接收的 bean 如下,使用 JSONReader.Feature.SupportSmartMatch ,依旧是使用 openid 这个字段名称。

  1.  
    @Data
  2.  
    public class XcUserEquityRequest {
  3.  
     
  4.  
     
  5.  
    @JSONField(name = "app_id")
  6.  
    private String appId;
  7.  
     
  8.  
     
  9.  
    @JSONField(name = "openid", deserializeFeatures= JSONReader.Feature.SupportSmartMatch)
  10.  
    private String openId;
  11.  
    }

请求的时候,依旧使用 open_id 下划线的形式。

学新通

 但是接口映射的openid字段为空。

学新通

官方对 SupportSmartMatch 的说明如下,

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhhkbegf
系列文章
更多 icon
同类精品
更多 icon
继续加载