时间:2023-01-30 10:34:23 | 栏目:JAVA代码 | 点击:次
Optional是Java8中增加的一个特性,它的出现是为了解决Java中的空指针问题,相关介绍可以参考这篇 Java8中的Optional操作;
但是在Jackson中操作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"}
但实际输出如下所示:
之所以序列化会输出{"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值;
幸运的是,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);
最后输出符合预期,如下所示:
Jackson在操作Optional类型的属性时,会由于Jackson自身的默认行为,导致输出的结果不符合预期;
解决办法就是加载jackson-datatype-jdk8
依赖,然后全局注册Java8模块Jdk8Module
;