Jackson 3.0.0-rc2 (minor update)
It has not been very long since Jackson 3.0.0-rc1 was released but in order to gather feedback quickly — to find issues with major version upgrade, specifically — we decided to release RC2 few days ago.
One driver for RC2 was a reported Gradle dependency problem in RC1 — but unfortunately turns out this was only partially resolved (see here for follow-up). So (some?) Gradle users may need to wait until RC3 (I am not 100% sure if there is a work-around).
But aside from this unfortunate problem, there are 3 updates in RC2 (over RC1) to consider.
1. Remove need to use @JsonSubTypes for Sealed Classes
One useful improvement in JDK 17 (the baseline for Jackson 3) is thing called “Sealed Classes” (see Baeldung’s article for explanation if not familiar). With regular classes, polymorphic handling with type names requires use of not only @JsonTypeInfo in the base class, but also adding references to sub-classes using either ObjectMapper.registerSubtypes() or (more commonly) @JsonSubTypes annotation like so:
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="type")
@JsonSubTypes({ @JsonSubTypes.Type(ImplX.class),
@JsonSubTypes.Type(ImplY.class),
@JsonSubTypes.Type(ImplZ.class)
})
abstract class BaseX { }but with sealed classes and Jackson 3.0.0-rc2, you only need @JsonTypeInfo as marker (and definition of which type id to use):
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="type")
abstract sealed class BaseX permits ImplX, ImplY, ImplZ { }which works pretty well as sub-type definitions are required for sealed classes anyway — and you no longer can accidentally forget them.
2. Extended Accessors for JsonNode
One of bigger efforts with 3.0 has been JSTEP-3 — improvements to Jackson Tree Model, that is, to JsonNode and its subtypes. There have been quite a few actual smaller improvements (see Javadocs for 3.0.0-rc2 as well as JSTEP-3), but there was one last bigger task left: unification and extension of “xxxValue() / asXxx()” accessors. Unification means making accessors work uniformly along same rules (for numbers, checking that value fits range; that specific coercions are similarly allowed/disallowed); and extensions means adding all variants similarly. Some of the work is just making use of other additions — for example, now that JacksonExceptions are unchecked, a new exception type JsonNodeException may be thrown by accessors in problem cases; something not possible to change in 2.x (for backwards-compatibility).
The last part of this unification/extension was implemented via [databind#5003] and [databind#5034], adding a set of accessors for following types:
int/long/BigIntegerdouble/BigDecimalStringboolean
There are 6 now different accessors for each of types listed, following pattern shown here for int accessors:
int intValue(): returnsintif (and only if) node contains Number that can be expressed as 32-bit Javaint; if not, will throwJsonNodeException.
Valid JSON values would include32(regular integer that fits in range),5.0(number with empty fraction), 7.01E3 (scientific-notation but still integer). Invalid values would be Strings (“abc”, “10”), Booleans, Numbers with non-empty fractions (2.57), numbers outside 32-bitintrange (1.0E100) and so on.int intValue(int defaultValue): Same asintValue()for validintvalues, but for non-valid will returndefaultValueinstead of throwingJsonNodeExceptionOptionalInt intValueOpt(): Same asintValue()(except for return type) but instead of throwingJsonNodeExceptionreturnsOptionalInt.empty()for non-valid node valuesint asInt(): Similar tointValue()if we have valid integral number (returned as-is), but will allow additional coercion from some representations.
Specifically will allow “Stringified” numbers (so String"137"would be returned asintvalue of137). For other value types, other coercions allowed (forboolean, integral values accepted).
Will thrown aJsonNodeExceptionif none of coercions applicableint asInt(int defaultValue): Same asasInt()but if coercions fail, will returndefaultValueinstead of throwingJsonNodeException.OptionalInt asIntOpt():Similar toasInt()(except for return type) but if coercions fail, will returnOptionalInt.empty()instead of throwingJsonNodeException.
Whoa! That’s quite a few methods added. Beyond this extensive set of accessors, there are a few supporting typed accessors (pre-existing but improved):
binaryValue()for both native Binary values (for formats that support them — Avro, CBOR, Protobuf, Smile) and Base64-encoded String values (JSON and other textual formats)floatValue()for 32-bit Javafloat(no coercions, regular type and range checks)numberValue()for accessing any of numeric types as its naturalNumberrepresentation (no coercions, no range checks needed)shortValue()for 16-bit Javashorts (no coercions, regular type and range checks)
Feedback wrt validation rules, ergonomics would be much appreciated.
3. Fix to getter/setter naming rules (no detecting island() :) )
And last & probably the least, [databind#2882] was fixed for 3.0.0-rc2 and following methods no longer infer properties:
public interface Beano {
// Used to produce "_value"; now ignored unless annotated
public int get_value();
// Used to produce "land"; - "" -
public boolean island();
// Would be expected to set property named "ter"
public void setter(int x);
}which should remove occasional odd cases of “where did THAT come from?” when serializing POJOs.
4. Towards 3.0.0-RC3
And the next step is releasing RC3. The plan is for it to:
- Finally fix Gradle dependency issue (… but we do need your help to verify!)
- Probably merge “Java 8 date/time” module (
jackson-datatype-jsr310) injackson-databind(one less module to have to register) — https://github.com/FasterXML/jackson-databind/pull/5032 - Replace core Reflection use with
MethodHandles— https://github.com/FasterXML/jackson-databind/pull/5046
When is that? Hopefully within next 2 weeks or so.
Happy Coding & Download with Care. :)
