Sitemap

Waiting for Jackson 2.19.0

4 min readApr 22, 2025

(what is in Jackson 2.19.0-rc2?)

Now that we have a release candidate for Jackson 2.19 — 2.19.0-rc2 (*) — it’s time to have a look at what goodies will be included. As usual, the full 2.19 release notes contain detailed list of all the changes; here we’ll look at biggest items.

(*) there is no rc1 — we had a problem with release process that resulted in needing to skip that version.

2.19 Stats

2.19 development has taken almost 6 months since 2.18.0 release, and there are over 80 changes (new features, fixes) across all official Jackson components — a bit more than 2.18 (with about 60 changes). Still, this can once again be classified as a “minor minor release” — partly due to now concurrent development work for finalizing 3.0.0 release (see this blog post for more) — with few bigger features but plenty of bug fixes.
As a result it is expected fewer regressions than with 2.18.0 where there was a major property introspection rewrite.

New modules: jackson-datatype-javax-money, -moneta

There are two related new modules for handling JSR-354 (Java Money) data types:

Modules were added in jackson-datatypes-misc repo and are added using standard module registration mechanism

ObjectMapper mapper = JsonMapper.builder()
.addModule(new JavaxMoneyModule())
.addModule(new MonetaMoneyModule())
.build();
String json = mapper.writeValueAsString(Money.of(29.95, "EUR"));

Most-Wanted feature: Support for @JsonWrapped with @JsonCreator

One particularly highly voted-for issue — [databind#1467] — was implemented for 2.19.
This basically (finally!) allows using of @JsonWrapped with @JsonCreator like so:

public record Point(int x, int y) { }

public class Rectangle {
private final Point origin;
private int width, height;

@JsonCreator
public Rectangle(@JsonProperty("origin") @JsonUnwrapped Point origin,
int width, int height) {
this.origin = origin;
this.width = width;
this.height = height;
}
public Point getOrigin() { return origin; }
public int getWidth() { return width; }
public int getHeight() { return height; }
}

This is particularly important for Java Record types which cannot have fields or setters; now @JsonUnwrapped can be used for Record types.
(same is true for immutable types in Kotlin and Scala)

JsonNode functionality improvements

JsonNode (Tree Model) got a few additional methods added, to support Java 8 Stream and Optional types:

  • [databind#2145]: Add optional(String) (Object nodes) and optional(int) (Array nodes) to complement existing get() and path() methods: both return Optional<JsonNode> with expected semantics (non-empty Optional if there is matching Property value/Array element; Optional.empty() if not)
  • [databind#4863]: Add basic Stream support: JsonNode.valueStream() for iterating over Object property values and Array elements, JsonNode.propertyStream() for iterating over Object properties (name/value pairs) and JsonNode.forEachEntry(BiConsumer<String, JsonNode>) for alternative way to iterate over Object properties.
  • [databind#4867]: Add JsonNode.asOptional() for essentially wrapping given JsonNode as Optional<JsonNode>— except for MissingNode which will become Optional.empty().
  • [databind#4955]: Add 2 remove methods in ContainerNode (that is, for ArrayNode and ObjectNode which are 2 implementations): removeIf(Predicate<? super JsonNode>) for general purpose removal of Array elements and Object property values, and removeNulls() as a convenience short-cut for removing NullNode s from Arrays or Objects.

Global default EnumNamingStrategy

Assigning naming strategy for “non-standard” Enums (ones where in-Java ALL_UPPER names need to map different in-JSON (external) convention) has been possible for a while using @EnumNaming annotation like so:

@EnumNaming(EnumNamingStrategies.LowerCamelCaseStrategy.class)
static enum EnumFlavorB {
PEANUT_BUTTER, SALTED_CARAMEL;
}
// in JSON now serialized as "peanutButter" and "saltedCaramel"

but until now there has not been any way to globally specify default naming convention (so default is “use Enum.name() as-is”) in case all (or most) your Enum types use different convention.

With [databind#4674] it is now possible to specify different default Enum naming strategy

ObjectMapper mapper = JsonMapper.builder()
.enumNamingStrategy(EnumNamingStrategies.LowerCamelCaseStrategy.INSTANCE)
.build();

which in turn may be overridden by @EnumNaming annotation on class.

Most Improved Modules: Avro, Java 8 date/time, Kotlin

In addition to above set of a dozen changes (all in jackson-databind), what else is changing? Majority of Jackson components had at least one change (see 2.19 Release Notes for details) but most noteworthy appear to be:

  • jackson-core (streaming): 7 fixes (2 for JsonPointer handling)
  • Data format modules in general, but Avro data format module (jackson-dataformat-avro) in particular: 5 fixes/improvements to Schema generation, Logical type handling
    (3 other format modules — CSV, XML, YAML — each had 2 fixes)
  • Java 8 date/time module (jackson-datatype-jsr310): 4 fixes (2 for deserialization, 1 for round-tripping (ser + deser) and 1 for performance optimization)
  • Kotlin module (jackson-module-kotlin): 15 changes!

What’s Next?

The plan is to release 2.19.0 soon, start 2.20 branch ((re)named as 2.x as per JSTEP-12), but focus even more on getting 3.0.0 ready for release.
Which reminds me that I need to write a bit about 3.0.0-rc3 that was also released recently.

--

--

@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

Responses (1)