阅读 102

Jackson处理Optional时遇到的问题

作者:汤圆

个人博客:javalover.cc

前言

Optional是Java8中增加的一个特性,它的出现是为了解决Java中的空指针问题,相关介绍可以参考这篇 Java8中的Optional操作 - 掘金 (juejin.cn);

但是在Jackson中操作Optional类型的属性时,会遇到一些问题,比如序列化的数据不符合预期等;

下面就来介绍下遇到的问题以及如何解决;

目录

  1. 序列化Optional类型的问题

  2. 原因分析

  3. 解决办法

正文

1. 序列化Optional类型的问题

其他类型的属性序列化时基本没啥问题,都会根据对象的值进行序列化;

但是Optional比较特殊,序列化时会输出present:true这样的数据;

下面我们看下例子;

这是User对象,其中nickname为Optional类型:

@Data @AllArgsConstructor @NoArgsConstructor public class User {     public String username;     public Optional<String> nickname; } 复制代码

序列化的代码如下所示:

User user = new User("jalon", Optional.of("xiaowang")); ObjectMapper objectMapper = new ObjectMapper(); String str = objectMapper.writeValueAsString(user); System.out.println(str); 复制代码

这里预期的结果应该是类似下面这样的:

{"username":"jalon","nickname":"xiaowang"} 复制代码

但实际输出如下所示:

image-20220215144754777

2. 原因分析

之所以序列化会输出{"present":true}这样的字符串,是因为Jackson默认的序列化行为导致;

Jackson默认的序列化会把所有public类型的get方法进行序列化,也就是取出对象中所有可访问的属性,然后填充到结果中;

而这里的Optional对象默认只有一个public类型的get方法,就是isPresent(),这个方法会返回true(当Optional的值不为空)或者false(当Optional的值为空);

Optional类的局部内容如下所示:

public final class Optional<T> {        private final T value;     public T get() {         if (value == null) {             throw new NoSuchElementException("No value present");         }         return value;     }     public boolean isPresent() {         return value != null;     }     @Override     public String toString() {         return value != null             ? String.format("Optional[%s]", value)             : "Optional.empty";     } } 复制代码

可以看到,虽然有一个value属性,但因为是private类型,所以无法直接被Jackson读取;

所以此时Jackson默认只读取了isPresent()方法,取得了true值;

3. 解决办法

幸运的是,Jackson官方已经出了一个maven依赖,专门用来解决 由于Java8新增的数据类型导致的各种问题;

添加如下依赖:

<dependency>     <groupId>com.fasterxml.jackson.datatype</groupId>     <artifactId>jackson-datatype-jdk8</artifactId>     <version>2.12.5</version> </dependency> 复制代码

然后在ObjectMapper对象中配置jdk8模块:objectMapper.registerModule(new Jdk8Module());

User user = new User("jalon", Optional.of("xiaowang")); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module()); String str = objectMapper.writeValueAsString(user); System.out.println(str); 复制代码

最后输出符合预期,如下所示:

image-20220215150501640

总结

Jackson在操作Optional类型的属性时,会由于Jackson自身的默认行为,导致输出的结果不符合预期;

解决办法就是加载jackson-datatype-jdk8依赖,然后全局注册Java8模块Jdk8Module


作者:汤圆学Java
链接:https://juejin.cn/post/7064830994490064933


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐