Taking Jackson 3.0.0-rc1 for a spin

@cowtowncoder
8 min readMar 16, 2025

--

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 groupIds 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:

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 support Records 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 DeserializationFeatures, SerializationFeatures 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 so java.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 modulesjackson-module-parameter-names and jackson-datatype-jdk8 — which add, respectively support for detecting Constructor parameter names (to avoid having to use @JsonProperty on Constructor parameter), and support for java.util.Optional and other Optional types. That is, you no longer need to add these 2 modules as ObjectMapper 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 extends RuntimeException (instead of Jackson 2.x JsonProcessingException which extends IOException).
    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 like YAMLMapper and XmlMapper) 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 using ObjectMapper.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 is SerializationContext (to go with its existing counterpart DeserializationContext)
  • Reduce use of “Json” prefix in type, method names, where functionality is not JSON-specific — for example, instead of JsonSerializers we now have ValueSerializers.

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) StreamTokens, change was considered too intrusive for things like custom deserializers
  • JsonNode: similarly, too widely used to make renaming worth the hassle (sub-types like ObjectNode do not have same problem)
  • While we now have TokenStreamFactory as the general type over now-specific JsonFactory (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 -> either StreamReadFeature or JsonReadFeature (one for format-agnostic, other for format-specific settings).
    NOTE: similarly all format-specific features now follow “XxxReadFeature” / “XxxWriteFeature” naming convention (so, like CsvReadFeature and CsvWriteFeature to use with CsvMapper)
  • 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:

  1. Some of new functionality added will be 3.x only (not back-ported in 2.x), but
  2. 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 new JsonNodeExceptions, access is extended to do proper coercion checks (these changes are included partially in rc1 and will be completed for rc2 )
  • ObjectMapper has methods for directly creating JsonParser / JsonGenerator instances (and ObjectReader 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).

--

--

@cowtowncoder
@cowtowncoder

Written by @cowtowncoder

Open Source developer, most known for Jackson data processor (nee “JSON library”), author of many, many other OSS libraries for Java, from ClassMate to Woodstox

No responses yet