When using Result objects with Jackson we might run into some problems. The Jackson datatype module for Result solves them by making Jackson treat results as if they were ordinary objects.
Jackson is a Java library for JSON parsing and generation. It is widely used for converting Java objects to JSON and vice versa, making it essential for handling data in web services and RESTful APIs.
How to Use this Add-On
Add this Maven dependency to your build:
Group ID
Artifact ID
Latest Version
com.leakyabstractions
result-jackson
Maven Central provides snippets for different build tools to declare this dependency.
Test Scenario
Let's start by creating a class ApiResponse containing one ordinary and one Result field.
/** Represents an API response */publicclassApiResponse { @JsonPropertyString version; @JsonPropertyResult<String,String> result;// Constructors, getters and setters omitted}
Problem Overview
Then we will take a look at what happens when we try to serialize and deserialize ApiResponse objects.
Java 8 optional type `java.util.Optional<java.lang.String>`
not supported by default:
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jdk8"
to enable handling
While this may look strange, it's the expected behavior. When Jackson examined the result object, it invoked Result::getSuccess and received an optional string value. But Jackson will not handle JDK 8 datatypes like Optional unless you register the appropriate modules.
@TestvoidtestSerializationProblem() {// GivenApiResponse response =newApiResponse("v1", success("Perfect"));// ThenObjectMapper objectMapper =newObjectMapper();InvalidDefinitionException error =assertThrows(InvalidDefinitionException.class, () ->objectMapper.writeValueAsString(response));assertTrue(error.getMessage().startsWith("Java 8 optional type `java.util.Optional<java.lang.String>` not supported"));}
This is Jackson's default serialization behavior. But we'd like to serialize the result field like this:
Cannot construct instance of `com.leakyabstractions.result.api.Result`
(no Creators, like default constructor, exist):
abstract types either need to be mapped to concrete types,
have custom deserializer, or contain additional type information
This behavior again makes sense. Essentially, Jackson cannot create new result objects because Result is an interface, not a concrete type.
What we want, is for Jackson to treat Result values as JSON objects that contain either a success or a failure value. Fortunately, there's a Jackson module that can solve this problem.
Registering the Jackson Datatype Module for Result
Finally, let's repeat the test again, this time with a failed result. We'll see that yet again we don't get an exception, and in fact, have a failed result.
We learned how to serialize and deserialize Result objects using Jackson, demonstrating how the provided datatype module enables Jackson to treat Results as ordinary objects.