侧边栏壁纸
  • 累计撰写 79 篇文章
  • 累计创建 84 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

Jackson处理Optional时遇到的问题

汤圆学Java
2022-02-15 / 0 评论 / 0 点赞 / 48 阅读 / 2,582 字
温馨提示:
本文最后更新于 2022-02-15,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

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

0

评论区