Waiting for Jackson 2.19.0
(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:
jackson-datatype-javax-money: for core Java Money data typesjackson-datatype-moneta: for supporting extended types in JSR-354 reference implementation
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) andoptional(int)(Array nodes) to complement existingget()andpath()methods: both returnOptional<JsonNode>with expected semantics (non-emptyOptionalif there is matching Property value/Array element;Optional.empty()if not) - [databind#4863]: Add basic
Streamsupport:JsonNode.valueStream()for iterating over Object property values and Array elements,JsonNode.propertyStream()for iterating over Object properties (name/value pairs) andJsonNode.forEachEntry(BiConsumer<String, JsonNode>)for alternative way to iterate over Object properties. - [databind#4867]: Add
JsonNode.asOptional()for essentially wrapping givenJsonNodeasOptional<JsonNode>— except forMissingNodewhich will becomeOptional.empty(). - [databind#4955]: Add 2 remove methods in
ContainerNode(that is, forArrayNodeandObjectNodewhich are 2 implementations):removeIf(Predicate<? super JsonNode>)for general purpose removal of Array elements and Object property values, andremoveNulls()as a convenience short-cut for removingNullNodes 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 forJsonPointerhandling)- 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.
