Jackson 中使用 Optional

介绍

在本文中,我们会对 Optional 类进行一些说明,并且会解释下如果在使用 Optional 类的时候可能在 Jackson 中进行序列化和反序列化的过程中出现的问题。

针对上面的问题,本文会将会介绍在 Jackson 中如何处理 Optional 对象,和如果 Optional 对象可能出现潜在的 Null 的解决方案。

问题概览

首先让我们来看看如果使用 Jackson 来对 Optional 数据类型进行序列化和反序列化中出现的问题。

Maven 依赖

针对 Jackson,我们可以使用最新的版本。

当我们对本文进行更新的时候,jackson-core 的最新版本为 2.17.0。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.13.3</version>
</dependency>

定义 Book 对象

随后让我们来定义一个 Book 对象,在 Book 对象中,我们有一个使用 Optional 的字段。

当然在这个 Book 对象中,我们还需要添加 Getter 和 Setter 方法,在文章中,我们就省略到这些方法了。

public class Book {

    private String title;
    private Optional<String> subTitle;
}

在的对数据对象进行初始化的时候,我们需要注意对 Optional 对象设置值的方式,因为不同的值会影响序列化和反序列化的情况。

序列化

让我们先来实例化 Book 这个对象:

Book book = new Book();
book.setTitle("Oliver Twist");
book.setSubTitle(Optional.of("The Parish Boy's Progress"));

随后,我们使用 Jackson 的 ObjectMapper 方法来对实例化后的对象进行序列化,我们使用下面的代码来进行序列化:

String result = mapper.writeValueAsString(book);

从输出的字段中,我们可以看到输出的字符串内容中并没有输出具体的值,而是输出为下面的内容:

{"title":"Oliver Twist","subTitle":{"present":true}}

尽管上面的输出看起来有点奇怪,但是上面的输出却是正确的情况,因为这个和 Optional 的特性是有关的。

方法 isPresent() Optional 的 public getter 方法,这就意味着在序列化的时候基于我们对象中存储的具体的值,Jackson 将会输出 True 或者 False 。

这是 Jackson 当前正确的输出方式。

但,我们可能考虑在输出的时候输出具体的值,至于怎么输出这个具体的值的方法,我们在后续的解决方案中提出。

反序列化

现在,让我们使用上面的代码来对对象数据进行反序列化,考察使用下面的代码:

@Test(expected = JsonMappingException.class)
public void givenFieldWithValue_whenDeserializing_thenThrowException
    String bookJson = "{ \"title\": \"Oliver Twist\", \"subTitle\": \"foo\" }";
    Book result = mapper.readValue(bookJson, Book.class);
}

当上面的代码运行的时候将会提示下面的错误信息:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.util.Optional` (no Creators, like default constructor, exist): no String-argument constructor/factory method to deserialize from String value ('foo')
 at [Source: (String)"{ "title": "Oliver Twist", "subTitle": "foo" }"; line: 1, column: 40] (through reference chain: com.ossez.jackson.optionalwithjackson.Book["subTitle"])

上面的错误信息针对 Jackson 来说是正确的,因为 Jackson 是需要一个构造方法来把 subtitle 参数的值来对 Optional 对象进行数据初始化。

解决方案

我们希望的是 Optional 对象应该把一个空的数据设置为 null,如果不是空的数据,Optional 应该使用值来进行处理。

针对上面的要求,Jackson 已经提供了解决方案,Jackson 针对 JDK8 的新增模块设置了一系列数据类型,这里就包括了 Optional。

Maven 依赖

首先,我们需要使用针对 JDK 8 使用的依赖,这个依赖的名称为:jackson-datatype-jdk8

<dependency>
   <groupId>com.fasterxml.jackson.datatype</groupId>
   <artifactId>jackson-datatype-jdk8</artifactId>
   <version>2.17.0</version>
</dependency>

现在,我们需要把上面的依赖注册到 ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());

或者上面的 2 句话也可以简化成 1 句话:

 ObjectMapper mapper = new ObjectMapper().registerModule(new Jdk8Module());

序列化

现在,让我们来进行测试。

让我们再次使用上面的代码来对 Book 这个对象进行序列化和反序列化,然后我们在对输出的字符串进行查看。

Book book = new Book();
book.setTitle("Oliver Twist");
book.setSubTitle(Optional.of("The Parish Boy's Progress"));
String serializedBook = mapper.writeValueAsString(book);
 
assertThat(from(serializedBook).getString("subTitle"))
  .isEqualTo("The Parish Boy's Progress");

如果我们尝试序列化一个空的 Book 对象的话,那么 Optional 字段中存储的数据为 null。

book.setSubTitle(Optional.empty());
String serializedBook = mapper.writeValueAsString(book);
 
assertThat(from(serializedBook).getString("subTitle")).isNull();

##反序列化
现在我们来进行反序列化,当我们进行反序列化的时候,我们可以看到上面的代码不再抛出 JsonMappingException 异常。

Book newBook = mapper.readValue(result, Book.class);
 
assertThat(newBook.getSubTitle()).isEqualTo(Optional.of("The Parish Boy's Progress"));

最后,我们再对上面的测试代码进行测试,从上面的代码代码输出中我们也可以看到没有异常,同时我们还得到了一个空的 Optional 对象。

assertThat(newBook.getSubTitle()).isEqualTo(Optional.empty());

结论

本文对针对 JDK 8 的新特性中提供的一些数据模型进行一些说明。

Jackson 需要注册一个新的 jdk8 数据类型才能对数据进行处理。

因为 Optional 是 JDK 8 中提供的新的数据特性,因此我们对一些新的数据类型我们需要有一些了解。

同时,针对 Jackson 还是有必要保持 JDK 的版本一致性和尽量使用比较高的版本,这样就可以使用更多有关 Jackson 提供的功能。

Jackson 中使用 Optional - Java - iSharkFly介绍在本文中,我们会对 Optional 类进行一些说明,并且会解释下如果在使用 Optional 类的时候可能在 Jackson 中进行序列化和反序列化的过程中出现的问题。 针对上面的问题,本文会将会介绍在 Jackson 中如何处理 Optional 对象,和如果 Optional 对象可能出现潜在的 Null 的解决方案。 问题概览首先让我们来看看如果使用 Jackson 来对 Optional 数据类型进行序列化和反序列…icon-default.png?t=N7T8https://www.isharkfly.com/t/jackson-optional/15713/1

  • 29
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HoneyMoose

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值