前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jaskson精讲第6篇-自定义JsonSerialize与Deserialize实现数据类型转换

Jaskson精讲第6篇-自定义JsonSerialize与Deserialize实现数据类型转换

作者头像
字母哥博客
发布2020-09-24 10:06:53
3.1K0
发布2020-09-24 10:06:53
举报

Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库。有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的,没有这种限制。它提供了很多的JSON数据处理方法、注解,也包括流式API、树模型、数据绑定,以及复杂数据类型转换等功能。它虽然简单易用,但绝对不是小玩具,更多的内容我会写成一个系列,5-10篇文章,请您继续关注我。

本节继续为大家介绍在Jackson序列化中经常遇到的一些特殊的数据类型,如LocalDateTime 。该如何进行序列化和反序列化。

一、LocalDateTime反序列化异常

首先我们定义一个java POJO实体类,其中关键的成员变量时birthDate,我们没有采用Date数据类型,而是采用了Java8 新的日期类型LocalDateTime ,使用LocalDateTime 的好处我就不多说了,有很多的文章解释说明。我们把精力放回到Jackson的JSON格式序列化与反序列化内容上来。

代码语言:javascript
复制
@Data
public class PlayerStar4 {
  private String name; //姓名
  private LocalDateTime birthDate; //出生日期
}

下面的代码,我们首先定义了一个PlayerStar4类的对象player,然后

  • 使用writeValueAsString方法将player对象序列化为JSON字符串jsonString
  • 然后使用readValue方法将JSON字符串jsonString ,反序列化为PlayerStar4类的对象
代码语言:javascript
复制
@Test
void testJSON2Object() throws IOException {

  ObjectMapper mapper = new ObjectMapper();

  PlayerStar4 player = new PlayerStar4();
  player.setName("curry");//我并不知道库里的生日,这里是编造的
  player.setBirthDate(LocalDateTime.of(1986,4,5,12,50));

  //将player对象以JSON格式进行序列化为String对象
  String jsonString = mapper.writeValueAsString(player);
  System.out.println(jsonString);

  //将JSON字符串反序列化为java对象
  PlayerStar4 curry = mapper.readValue(jsonString, PlayerStar4.class);
  System.out.println(curry);

}

但是上面的代码报错了,从下图中可以看出

  • 将player对象序列化为JSON字符串jsonString 的过程被正常执行了,但是LocalDateTime序列化之后的结果,是图中”黄框中的黄框“内容。
  • 将JSON字符串反序列化的过程报错了,因为Jackson默认情况下,根本不认识图中”黄框中的黄框“内容这种LocalDateTime序列化之后的JSON字符串数据结构。无法把它反序列化为java对象。

怎么办?我们需要自定义序列化及反序列化类型转换器,有两种方法

  • 继承StdConverter类,自定义实现String与LocalDateTime相互转换
  • 继承JsonSerializer和JsonDeserializer类,自定义实现String与LocalDateTime相互转换

二、方法一:继承StdConverter类

继承StdConverter类,将LocalDateTime序列化为String数据类型

代码语言:javascript
复制
public class LocalDateTimeToStringConverter extends StdConverter<LocalDateTime, String> {
  static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);

  @Override
  public String convert(LocalDateTime value) {
      return value.format(DATE_FORMATTER);
  }
}

继承StdConverter类,将String数据类型反序列化为LocalDateTime

代码语言:javascript
复制
public class StringToLocalDatetimeConverter extends StdConverter<String, LocalDateTime> {
  @Override
  public LocalDateTime convert(String value) {
      return LocalDateTime.parse(value, LocalDateTimeToStringConverter.DATE_FORMATTER);
  }
}

自定义的转换器完成之后,我们就可以在对应的成员变量上,使用@JsonSerialize指定序列化转换器,@JsonDeserialize指定反序列化转换器。

代码语言:javascript
复制
  @JsonSerialize(converter = LocalDateTimeToStringConverter.class)
  @JsonDeserialize(converter = StringToLocalDatetimeConverter.class)
  private LocalDateTime birthDate;

然后调用第一小节中的测试用例,就不会出现异常了。控制台打印输出结果如下,第一行是序列化结果JSON格式字符串,第二行是Java 对象的toString()方法的打印结果。

代码语言:javascript
复制
{"name":"curry","birthDate":"1986-4-5 12:50:00"}
PlayerStar4(name=curry, birthDate=1986-04-05T12:50)

三、方法二:继承JsonSerializer和JsonDeserializer类

继承JsonSerializer<LocalDateTime>类,将LocalDateTime序列化为String数据类型

代码语言:javascript
复制
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
  static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);

  @Override
  public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider)
          throws IOException {
          String s = value.format(DATE_FORMATTER);
          gen.writeString(s);
  }
}

继承JsonDeserializer<LocalDateTime>类,将String数据类型反序列化为LocalDateTime

代码语言:javascript
复制
public class LocalDatetimeDeserializer extends JsonDeserializer<LocalDateTime> {

  @Override
  public LocalDateTime deserialize(JsonParser p, DeserializationContext ctx)
          throws IOException {
      String str = p.getText();
      return LocalDateTime.parse(str, LocalDateTimeSerializer.DATE_FORMATTER);
  }
}

四、如果上面的你都没看懂

对于相对小白的读者,上面的自定义序列化及反序列化转换过程你都没懂,对于LocalDateTime的异常你也不要慌,Jackson已经给出了解决方案。

需要特别和大家强调的是LocalDateTimeSerializer和LocalDateTimeDeserializer其实并不需要我们自己去定义,因为Jackson已经帮我们定义好了。 之所以我还做了自定义的实现的介绍,是因为要为大家讲解这个自定义序列化和反序列化类型转换的实现过程,以后你再遇到其他的特殊的数据类型转换,或者LocalDateTime类型的特殊日期格式等,都可以自己来定义JsonSerialize和JsonDeserialize来实现数据类型的转换。

下面的这两个类就是Jackson已经帮我们定义好的LocalDateTimeSerializer和LocalDateTimeDeserializer。

代码语言:javascript
复制
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

使用方法是在对应的成员变量上,使用@JsonSerialize指定序列化转换器,@JsonDeserialize指定反序列化转换器。

代码语言:javascript
复制
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime birthDate;

执行之后的序列化和反序列化结果,和方法一、方法二自定义的实现效果是一样的。

喜欢 (0)or分享 (0)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、LocalDateTime反序列化异常
  • 二、方法一:继承StdConverter类
  • 三、方法二:继承JsonSerializer和JsonDeserializer类
  • 四、如果上面的你都没看懂
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档