Taking Jackson 3.0.0-rc1 for a spin
Now that the first pre-release version of Jackson 3 — 3.0.0-rc1 — has been released (last week on March 7, 2025 to be exact), it is a good time to try it out. While this version is not ready (or meant) for a “real” use, it should give a good idea of changes Jackson 3 will bring over current 2.x versions (latest being 2.18.3). Testing this version can also help Jackson project if you have feedback to share: bugs to report, features or changes suggest.
So let’s see how to try it out.
Basic Requirements for using Jackson 3.x
To try out Jackson 3.0.0-rc1
you:
- Need to use JDK 17 or latest (Jackson 2.x requires JDK 8 or above)
- Should be familiar with Jackson 2.x API — while 3.0 is a major version upgrade, the core external API entry points are very similar. Or if you are not familiar with it you can read any Jackson 2.x tutorial to learn the basics.
and that’s it.
Getting Jackson 3.0.0-rc1
As with earlier Jackson versions, 3.0 is published to Maven Central repository, and accessed using Maven or other Maven repository compatible build tool such as Gradle.
Coordinates for Jackson 3.x components are similar to those of Jackson 2.x: artifactId
s remain same but groupId
s now start with tools.jackson
(instead of com.fasterxml.jackson
) — with one exception: jackson-annotations
package is still under com.fasterxml.jackson
— groupId.
So, for basic usage you would typically add dependencies in pom.xml
like this:
<dependencies>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>3.0.0-rc1</version>
</dependency>
// and possibly annotations too (altho transient dependency of databind)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>3.0-rc1</version>
</dependency>
</dependencies>
(when using Maven, modify appropriately for Gradle)
or, better yet, use jackson-bom
for consistent version set (if not familiar with BOMs, read f.ex this blog post):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>3.0.0-rc1</version> <!-- Use the latest version -->
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<!-- and with that, can omit version element from actual dependencies -->
<dependencies>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
</dependencies>
Using 3.0.0-rc1 (simple)
Having dependencies added, you can use the good old ObjectMapper
. Old code like this would still work fine — with the caveat that Java packages have also moved from com.fasterxml.jackson
to tools.jackson
(except for jackson-annotations
):
import tools.jackson.databind ObjectMapper;
public class MyTest {
public static void main(String[] args) {
final ObjectMapper mapper = new ObjectMapper(); // old style, 2.x
Point p = mapper.readValue("""
{
"x": 1,
"y": 2
}
""");
p = p.moveBy(-1, 3);
String json = mapper.writerWithDefaulPrettyPrinter()
.writeValueAsString(p);
System.out.println("JSON: "+json);
}
In practice you would likely construct your ObjectMapper
slightly differently: if you need any configuration, you will need to use “builder” pattern (optional in 2.x, now mandatory in 3.0 with Immutable core objects like ObjectMapper
and JsonFactory
):
final ObjectMapper mapper = JsonMapper.builder() // format-specific builders
.addModule(new JavaTimeModule()) // to use "java.time" types
.enable(JsonWriteFeature.ESCAPE_NON_ASCII) // does what it says
.build();
Another change you might notice: with 3.0, you no longer need to declare or catch IOException
— Jackson API has been changed so that the new base exception — JacksonException
— extends unchecked RuntimeException
, not (checked) IOException
. This simplifies usage with Java 8 Streams (for example).
So Why Actually Use Jackson 3.0?
Beyond just “trying out new things”, what would be reasons to (eventually) use Jackson 3.x, over well-established, mature Jackson 2.x (and thereby motivate trying out 3.0.0-rc1)?
I will be writing more about changes included, as well as full reasons behind 3.x development, but here is some reading if you have time:
- Jackson 3.0 vision (Jan 2021) explains reasoning for developing a new major version (instead of just continuing with new 2.x versions)
- 3.0.0 Release Notes page lists all accumulated changes so far, with links to issues and PRs
TL;DNR: ultimately Jackson 3.0 is / will be all about making changes that cannot be made in Jackson 2.x series due to backwards-compatibility constraints. While 2.x has served us well — 2.0.0 was released all the way back in March 2012 — almost 13 years ago! — it is starting to show its age.
At high level, changes can be grouped like so:
- More modern Java Baseline (require JDK 17, support/use JPMS)
- Better ergonomics (default settings, more bundled functionality, unchecked exceptions, convenient+safe builder-pattern for configuration)
- API clean up: Removal of Deprecated functionality, types, methods
- Improved, more consistent naming (no more “JSONxxx” unless JSON-specific)
- Improved performance for data-binding
- New features only for 3.x
Let’s have a look at all these improvement areas.
Jackson 3.0: more modern Java Baseline
With 3.0, Jackson now requires JDK 17 as the minimum version (choice of 17 as baseline over requiring 21 is discussed here, fwtw) over now ancient JDK 8 (required by Jackson 2.x).
This upgrade makes possible:
- Direct support for
Record
types (Jackson 2.x does supportRecord
s but needs a bit of Reflection access), simplifying supporting code - Native support for JPMS (Java Platform Module System) — directly define
module-info.java
, build system validates and verifies (Jackson 2.x does produce module info, but using Moditect plug-in to build with pre-JPMS JDKs). This should significantly improve JPMS compatibility of Jackson - Can add support for polymorphism wrt “Sealed Classes” with less annotations (avoid
@JsonSubTypes
) - Implementation can make use of all goodies JDK itself has added, to simplify code, make easier to read, maintain and so on
So this mainly improves stability of Jackson and opens up possibility of future improvements.
Jackson 3.0: better ergonomics
A big area of improvements is that of ergonomics: improving ease-of-use.
This includes things like:
- Changing default settings (which
DeserializationFeature
s,SerializationFeature
s and so on are enabled by default). Changes are based on observed usage, default settings by frameworks like Spring Boot and user feedback via issues. The goal for changing defaults is to reduce the need for users to override defaults: try to make the default settings as likely as possible to work for most common use cases.
The full set (?) of changes is documented on JSTEP-2 page (and some of changes discussed here), but just as an example,SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
is now disabled by default sojava.time.OffsetDateTime
will be serialized as ISO-8601 JSON String, instead of milli-second -based timestamp (JSON Number). - Inclusion of functionality from 2 of Java 8 modules —
jackson-module-parameter-names
andjackson-datatype-jdk8
— which add, respectively support for detecting Constructor parameter names (to avoid having to use@JsonProperty
on Constructor parameter), and support forjava.util.Optional
and other Optional types. That is, you no longer need to add these 2 modules asObjectMapper
already supports functionality they used to contain in Jackson 2.x.
(NOTE: 3rd Module,jackson-datatype-jsr310
, is still separate, to allow for configurability — so you typically do need to add it) - Changing exceptions thrown by Jackson to be unchecked: new base exception,
JacksonException
extendsRuntimeException
(instead of Jackson 2.xJsonProcessingException
which extendsIOException
).
This removes the need to convert exceptions to unchecked (or to use “sneaky throws”) when using Java 8 Streams, lambdas and so on. - Exposing full, safe configurability via Builder pattern, making
ObjectMapper
s (including format-specific subtypes likeYAMLMapper
andXmlMapper
) fully immutable, safely sharable — no longer need to avoid accidental “config-after-use” since it is no longer technically possible.
NOTE: it is also possible to “re-configure” mappers by usingObjectMapper.rebuild()
which just creates new Builder from existing instance — once again safely rebuilding a new, unconnected Mapper instance.
Jackson 3.0: API clean up (removal of Deprecated Stuff)
One of the very first done when creating new Git branch for 3.0 work — back in 2017! — was to start removing things marked as @Deprecated
. Eventually almost all deprecated things (functionality like Format auto-detection; classes; method overloads) were removed, although some exceptions were made for latest deprecations — for example, although JsonNode.asString()
was added as improved naming (see next section), the old variant JsonNode.asText()
remains as @Deprecated
in 3.0 to allow a bit more gradual upgrading.
The benefit of removal is mainly for maintainers — a bit less code to maintain — but it also reduces fluff in API docs users need to ignore, and ideally slightly reduce cognitive load.
Jackson 3.0: Better Naming (less of “JsonXxx”)
Another big area of non-functional changes is that of “Big Rename”, outlined in JSTEP-6. Main goals are:
- Unify terminology: f.ex, JSON Objects have “properties” instead of “fields” or “entries” (all of which were used in 2.x API); and instead
SerializerProvider
there isSerializationContext
(to go with its existing counterpartDeserializationContext
) - Reduce use of “Json” prefix in type, method names, where functionality is not JSON-specific — for example, instead of
JsonSerializer
s we now haveValueSerializer
s.
Of these, second one has a few exceptions: “Json” prefix remains in places like:
- Annotation names are left as-is: this is required to keep 2.x and 3.x annotations backwards AND forwards-compatible (can still use 2.x annotations with Jackson 3.x functionality). So we still have
@JsonProperty
annotation and not f.ex@JacksonProperty
JsonToken
: while these should be (if starting from scratch)StreamToken
s, change was considered too intrusive for things like custom deserializersJsonNode
: similarly, too widely used to make renaming worth the hassle (sub-types likeObjectNode
do not have same problem)- While we now have
TokenStreamFactory
as the general type over now-specificJsonFactory
(sub-type), 2 other abstractions —JsonParser
,JsonGenerator
— were left as-is.
Changes made include:
- Exceptions:
JsonProcessingException
->JacksonException
;JsonParseException
->StreamReadException
;JsonMappingException
->DatabindException
- Read/Write features:
JsonParser.Feature
-> eitherStreamReadFeature
orJsonReadFeature
(one for format-agnostic, other for format-specific settings).
NOTE: similarly all format-specific features now follow “XxxReadFeature” / “XxxWriteFeature” naming convention (so, likeCsvReadFeature
andCsvWriteFeature
to use withCsvMapper
) JsonStreamContext
->TokenStreamContext
,JsonLocation
->TokenStreamLocation
JsonSerializable
->JacksonSerializable
Jackson 3.0: Improved performance
Another area of improvement is performance: 3.0 does contain significant improvements to mapping of POJO properties databind — some ideas of Jackson Afterburner module were included in handling.
Over time it is also likely that new optimizations from later JDKs may be incorporated.
Jackson 3.0: New 3.0-only features
While the initial release does not contain much unique functionality over 2.x series, over time:
- Some of new functionality added will be 3.x only (not back-ported in 2.x), but
- Almost all functionality added in 2.x will be included in 3.x as well
So effectively 3.x will be gaining net-new functionality once 2.x development starts dwindling down.
Still, there is already some functionality in 3.0.0-rc1 that will not be part of 2.x versions:
- Additions/changes to
JsonNode.xxxValue()
/JsonNode.asXxx()
methods — with the ability to throw newJsonNodeException
s, access is extended to do proper coercion checks (these changes are included partially inrc1
and will be completed forrc2
) ObjectMapper
has methods for directly creatingJsonParser
/JsonGenerator
instances (andObjectReader
for former,ObjectWriter
for latter)
Next Steps?
We would love to hear from you! If you do try things out and find something you find worth discussing — problems/concerns, ideas? — reach to out via https://github.com/FasterXML/jackson/discussions/.
In the meantime, we are planning for 3.0.0-rc2 release, to occur some time in late-March/early-April 2026 (see this GH Discussion).