www.baeldung.com Open in urlscan Pro
172.66.43.8  Public Scan

Submitted URL: http://www.baeldung.com/jackson-optional
Effective URL: https://www.baeldung.com/jackson-optional
Submission: On August 09 via manual from GB — Scanned from US

Form analysis 0 forms found in the DOM

Text Content

 * 
 * 
 * Start Here
 * Courses ▼▲
   
   
    * REST WITH SPRING BOOT
      
      The canonical reference for building a production grade API with Spring
   
   
    * LEARN SPRING SECURITY ▼▲
      
      THE unique Spring Security education if you’re working with Java today
      
      
       * LEARN SPRING SECURITY CORE
         
         Focus on the Core of Spring Security 6
      
      
       * LEARN SPRING SECURITY OAUTH
         
         Focus on the new OAuth2 stack in Spring Security 6
   
   
    * LEARN SPRING
      
      From no experience to actually building stuff
   
   
    * LEARN SPRING DATA JPA
      
      The full guide to persistence with Spring Data JPA

 * Guides ▼▲
   
   
    * PERSISTENCE
      
      The Persistence with Spring guides
   
   
    * REST
      
      The guides on building REST APIs with Spring
   
   
    * SECURITY
      
      The Spring Security guides

 * About ▼▲
   
   
    * FULL ARCHIVE
      
      The high level overview of all the articles on the site.
   
   
    * BAELDUNG EBOOKS
      
      Discover all of our eBooks
   
   
    * ABOUT BAELDUNG
      
      About Baeldung.
   
   
    * WRITE FOR BAELDUNG
      
      Become a writer on the site.

 * 
 * 


 1. 1. Introduction
 2. 2. Problem Overview
    1. 2.1. Maven Dependency
    2. 2.2. Our Book Object
    3. 2.3. Serialization
    4. 2.4. Deserialization
 3. 3. Solution
    1. 3.1. Maven Dependency and Registration
    2. 3.2. Serialization
    3. 3.3. Deserialization
 4. 4. Conclusion


USING OPTIONAL WITH JACKSON

Powered By

00:06/08:08
10 Sec

80.5M

133
Spring Security - Remember Me with Persistence (LSS - Module 3 - Lesson 3)




Next
Stay






Last updated: August 18, 2023

Written by: baeldung
 * Data
 * Jackson

 * Jackson Basics
 * Java Null
 * Optional




 


1. INTRODUCTION



In this article, we’ll give an overview of the Optional class, and then explain
some problems that we might run into when using it with Jackson.

Following this, we’ll introduce a solution which will get Jackson to treat
Optionals as if they were ordinary nullable objects.


2. PROBLEM OVERVIEW



First, let’s take a look at what happens when we try to serialize and
deserialize Optionals with Jackson.


2.1. MAVEN DEPENDENCY



To use Jackson, let’s make sure we’re using its latest version:



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


2.2. OUR BOOK OBJECT



Then, let’s create a class Book, containing one ordinary and one Optional field:

public class Book {
   String title;
   Optional<String> subTitle;
   
   // getters and setters omitted
}Copy

Keep in mind that Optionals should not be used as fields and we are doing this
to illustrate the problem.


2.3. SERIALIZATION



Now, let’s instantiate a Book:

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

And finally, let’s try serializing it using a Jackson ObjectMapper:

String result = mapper.writeValueAsString(book);Copy

We’ll see that the output of the Optional field, does not contain its value, but
instead a nested JSON object with a field called present:



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

Although this may look strange, it’s actually what we should expect.

In this case, isPresent() is a public getter on the Optional class. This means
it will be serialized with a value of true or false, depending on whether it is
empty or not. This is Jackson’s default serialization behavior.

If we think about it, what we want is for actual the value of the subtitle field
to be serialized.


2.4. DESERIALIZATION



Now, let’s reverse our previous example, this time trying to deserialize an
object into an Optional. We’ll see that now we get a JsonMappingException:

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

Let’s view the stack trace:



com.fasterxml.jackson.databind.JsonMappingException:
  Can not construct instance of java.util.Optional:
  no String-argument constructor/factory method to deserialize from String value ('The Parish Boy's Progress')Copy

This behavior again makes sense. Essentially, Jackson needs a constructor which
can take the value of subtitle as an argument. This is not the case with our
Optional field.


3. SOLUTION



What we want, is for Jackson to treat an empty Optional as null, and to treat a
present Optional as a field representing its value.

Fortunately, this problem has been solved for us. Jackson has a set of modules
that deal with JDK 8 datatypes, including Optional.


3.1. MAVEN DEPENDENCY AND REGISTRATION



First, let’s add the latest version as a Maven dependency:



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

Now, all we need to do is register the module with our ObjectMapper:

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


3.2. SERIALIZATION



Now, let’s test it. If we try and serialize our Book object again, we’ll see
that there is now a subtitle, as opposed to a nested JSON:

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");Copy

If we try serializing an empty book, it will be stored as null:

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


3.3. DESERIALIZATION



Now, let’s repeat our tests for deserialization. If we reread our Book, we’ll
see that we no longer get a JsonMappingException:



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

Finally, let’s repeat the test again, this time with null. We’ll see that yet
again we don’t get a JsonMappingException, and in fact, have an empty Optional:

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


4. CONCLUSION



We’ve shown how to get around this problem by leveraging the JDK 8 DataTypes
module, demonstrating how it enables Jackson to treat an empty Optional as null,
and a present Optional as an ordinary field.

The implementation of these examples can be found over on GitHub; this is a
Maven-based project, so should be easy to run as is.

Course – LS – NPI (cat=JSON/Jackson)



Get started with Spring Boot and with core Spring, through the Learn Spring
course:

>> CHECK OUT THE COURSE

res – Jackson (eBook) (cat=Jackson)
Do JSON right with Jackson
Download the E-book

eBook – Jackson – NPI (cat=Jackson)
Do JSON right with Jackson
Download the E-book





COURSES

 * All Courses
 * All Bulk Courses
 * All Bulk Team Courses
 * The Courses Platform

SERIES

 * Java “Back to Basics” Tutorial
 * Jackson JSON Tutorial
 * Apache HttpClient Tutorial
 * REST with Spring Tutorial
 * Spring Persistence Tutorial
 * Security with Spring
 * Spring Reactive Tutorials

ABOUT

 * About Baeldung
 * The Full Archive
 * Editors
 * Our Partners
 * Partner with Baeldung
 * eBooks

 * Terms of Service
 * Privacy Policy
 * Company Info
 * Contact




Freestar.com