开发工具分享
  • 首页
  • 计算科学
  • 文化旅游
  • 项目和网站
    • OSSEZ 计算技术
    • USRealEstate 社区
    • 地区文化
    • CWIKI.US
    • BUG.OSSEZ.COM
    • RSS.OSSEZ.COM
CWIKIUS.CN
一个有独立思考和温度的清新站
  1. Home
  2. Computer Science
  3. This article

Jackson 中使用 Optional

2024年05月06日 415Browse 0Like 0Comments

介绍

在本文中,我们会对 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 提供的功能。

 

https://www.isharkfly.com/t/jackson-optional/15713/1

Tags: None
Last updated:2024年05月06日

HoneyMoose

有温度的人文和独立的思考

Like
< Previous
Next >

Comments

Cancel reply

Archives
  • May 2026
  • April 2026
  • March 2026
  • February 2026
  • January 2026
  • December 2025
  • November 2025
  • October 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
Categories
  • Computer Science (2,362)
    • Confluence (663)
    • Gradle (12)
  • U.S. (482)
  • 文化旅游 (145)

COPYRIGHT © 2020 CWIKIUS. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

湘ICP备2020018253号-1