Jackson 2.17 released
Only about 4 months after Jackson 2.16.0 release, we now have Jackson 2.17.0 available (see 2.17 Release Notes) (*). Timeline was somewhat condensed as this released focused on bug fixes without many “big” features. But even with that compact timeline we managed to include no fewer than 100 (!) fixes, improvements and features.
Let’s have a look at some of most noteworthy inclusions.
(*) ok, yes, it has been almost 4 weeks since release. Someone’s been procrastinating writing this Blog Post :)
Most Wanted New Feature: Fail on Properties not part of View
Of highly voted (and labeled as most-wanted
) Github issues, one was implemented — jackson-databind#437 — for 2.17 (leaving 10 most-wanted for later releases :) )
It adds a new feature, DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES
, enabling of which enforces limit that only those properties included in the currently active View are allowed: encountering any other JSON Object property will throw a MismatchedInputException
.
Feature can be enabled by default on ObjectMapper
, or on specific ObjectReader
and used like so:
ObjectMapper mapper = JsonMapper.builder()
.enable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
// or:
ObjectReader r = mapper.readerFor(MyValue.class)
.with(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.withView(View1.class);
MyValue value = r.readValue(jsonString);
Note: “unexpected” here refers to POJO properties that are known (and not “unknown properties”) but not part of the active View — whether failure occurs for unknown properties is controlled with DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
.
Important New Feature: Escape forward slashes too
Another important new feature — core#507 — that has been requested multiple times in the past, is the ability to automatically escape forward slash (/
) characters on output. While this character is not required to be escaped by JSON specification, its escaping is useful for one important use case: when embedding JSON in HTML or Javascript escapingprevents security issues due to possibility if including JSON Strings with XML end tag like </script>
.
While it has been possible to implement this functionality using existing CharacterEscapes
abstraction, the new feature has 2 main benefits over that approach:
- Convenience (one line configuration)
- Performance (negligible overhead, compared to measurable (if not high) for
CharacterEscapes
)
The feature can be enabled directly on JsonFactory
(to be used for all output):
JsonFactory f = JsonFactory.builder()
.enable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)
.build();
ObjectMapper mapper = JsonMapper.builder(f).build();
or via ObjectWriter
on as-needed basis:
ObjectMapper mapper = ...
ObjectWriter w = mapper.writer()
.with(JsonWriteFeature.ESCAPE_FORWARD_SLASHES);
String safeJson = w.writeValueAsString(myValue);
// or disable escaping since URLs "look funny":
w = writer.without(JsonWriteFeature.ESCAPE_FORWARD_SLASHES);
String neatJson = w.writeValueAsString(myValue);
Either way, instead of getting JSON like:
{ "message": "nasty: </script>" }
output would be
{ "message": "nasty: <\/script>" }
Feature is not enabled by default, for backwards compatibility, but may be enabled by default in Jackson 3.0 (no firm decision yet) if that is deemed important from safety perspective (default settings to favor safety of all common use cases).
Most Improved components: XML, Ion, Kotlin, jackson-jr
Aside from core modules (jackson-core, jackson-databind, jackson-databind) — which typically get most improvements (especially jackson-databind) — this time around 4 other components were notably improved.
Most improved format module: Ion (12 fixes)
jackson-dataformat-ion has 12 resolved issues: almost all were improvements to handling of corrupt content, addressing issues found by OSS-Fuzz testing (“fuzzing”). Fixes were through underlying codec library, ion-java, made by library maintainer (Tyler G, kudos!).
While there are not many new features, Ion decoding robustness (error detection, reporting) improved a lot with Jackson 2.17 which is great for production use.
Second most improved format module: XML (6 fixes)
jackson-dataformat-xml has 6 resolved issues.
Most notable ones are dataformat-xml#324 and dataformat-xml#634, which add explicit support for XML Schema xsi:type
attribute.
Basically they enable automatic conversion between logical name "xsi:type"
for Jackson polymorphic type id, and underlying fully-qualified XML attribute name (324 for writing XML, 634 for reading XML); handling is enabled by using two new features:
ToXmlGenerator.Feature.AUTO_DETECT_XSI_TYPE
FromXmlParser.Feature.AUTO_DETECT_XSI_TYPE
which you enable (they are disabled by default for backwards-compatibility) by:
XmlMapper XSI_ENABLED_MAPPER = XmlMapper.builder()
.configure(ToXmlGenerator.Feature.AUTO_DETECT_XSI_TYPE, true)
.configure(FromXmlParser.Feature.AUTO_DETECT_XSI_TYPE, true)
.build();
and usage (example from XsiTypeReadTest
) is like so:
@JsonRootName("Poly")
@JsonTypeInfo(use = Id.SIMPLE_NAME, include = As.PROPERTY, property="xsi:type")
class PolyBean {
public int value;
protected PolyBean() { }
public PolyBean(int v) { value = v; }
}
final String XML = XSI_ENABLED_MAPPER.writeValueAsString(new PolyBean(42));
PolyBean result = XSI_ENABLED_MAPPER.readValue(XML, PolyBean.class);
assertEquals(42, result.value);
The main use case is one where interoperability with XML -centric tools (like JAXB) is needed: ability to use XML Schema standard type discriminator (xsi:type
) makes it much easier to use Jackson in heterogenous systems where different endpoints (client/server/broker) use different tech stack.
Improved component: jackson-jr
Jackson-jr also saw more than usual number of improvements — 10 issues resolved.
Many addressed smaller issues that were reported a few versions back; overall there were many usability improvements.
Notable ones:
- #7: Support deserialization of
int[]
valued properties - #25: Add support for single-int Constructors
- #51: Duplicate key detection does not work for (simple) Trees
- #78: Deserializes “null” to “0.0” for
java.lang.Double
(wrapper) - #93: Skip serialization of
groovy.lang.MetaClass
values to avoidStackOverflowError
- #94: Support for serializing Java Records (but not deserialization)
- #100: Add minimal support for
java.time
(Java 8 date/time) types (NOTE: onlyLocalDateTime
at first, but allows for easier extension to support other types) - #116: Add read/write support for
java.nio.file.Path
Hopefully we will see even more improvements to jackson-jr in near future: it is still relatively easy to make a positive difference with contributions (read: “Contributors Welcome!”)
Improved module: Kotlin
Kotlin module saw TONS of improvements — in fact, 16 issues were resolved; some were for maintenance reasons (deprecating functionality), but many addressed performance issues reported: Jackson 2.17 Kotlin module should perform significantly better than earlier versions.