Skip to content

JSTEP 1

Tatu Saloranta edited this page Nov 30, 2024 · 19 revisions

(Back to JSTEP page)

Major Version 3.x High-level Upgrade Compatibility

Author

Tatu Saloranta (@cowtowncoder)

Version history

  • 2024-04-29: Update based on current status, thinking
  • 2022-06-29: major change to Coordinates (com.fasterxml -> tools.jackson!)
  • 2021-01-29: small clarifications
  • 2019-02-09: minor touchup
  • 2019-01-26: first revision

Status

Mostly complete as of Jackson 2.18: implemented as proposed.

TL; DNR;

The basic proposal now is that for Jackson 3, we will change

  • Maven coordinates AND Java package names and SOME (but not all) Java class names
    • exception being jackson-annotations, for which none of above would be changed
  • Maven coordinate change (minus annotations) would be changing group id base from com.fasterxml.jackson to tools.jackson (that is, from com.fasterxml.jackson.core to tools.jackson.core)
    • CREDITS: suggestion for tools.jackson was by Sergei Egorov
    • Potentially open question: how about Artifact Id? Do we keep jackson-core or change to jackson3-core?
      • Some expressed desire for unique artifact ids for usage where jar names must be unique to allow Jackson 2.x / 3.x co-existence
      • Note: Jackson 1.x -> 2.x did change names of many artifacts (jackson-mapper-asl -> jackson-databind), but not all
      • Current plan is NOT to change artifact id.
  • Java package name change, similarly, would be com.fasterxml.jackson to tools.jackson
  • jackson-annotations would be a special case in that it would CONTINUE USING jackson 2.x Maven artifact and Java package names
    • this implies that Jackson 2.x could use Jackson 3.x annotation package, and vice versa: this is indeed the intent -- no need for duplication of annotations unlike with Jackson 1.x -> 2.x upgrade

For full details and discussion on why proposal is like this, continue reading.

Background

Jackson follows Semantic Versioning, and as such Major Version change planned from 2.x to 3.0 indicates major, backwards-incompatible changes. Such changes are made in order to improve Jackson in ways that would not otherwise be possible, including (but not limited to) things like:

  • Removal of deprecated methods in public API (note: Jackson minor versions allow more aggressive removal of internal methods)
  • Changes to required abstract methods (for abstract classes and interfaces)
  • Renaming of public API classes
  • Changes to default settings, behavior

A particular important reason for this specific upgrade, however, is the desire to make 2 core abstractions fully immutable: ObjectMapper and JsonFactory (now renamed as TokenStreamFactory). This requires combination of above changes, and can not be done in a way that retains Jackson 2.x source level compatibility.

Prior art

Jackson has already undergone one major version upgrade: from 1.9 to 2.0. We consider that upgrade largely successful and positive, due to changes taken to avoid class-loading collisions across 1.x and 2.x, which essentially allow 1.x and 2.x implementations to co-exist within same JVM. There are of course downsides -- there is no perfect way to upgrade; and it could be argued that need to do major upgrade is a sign of fundamental problems with upgrade -- main complaint being that upgrade process even for simplest cases is more involved than just upgraded dependency version number.

What was done with 1.9-to-2.0 upgrade can be summarized as:

  1. Move root Java package from org.codehaus.jackson to com.fasterxml.jackson, to avoid class collisions
  2. Change Maven group id from org.codehaus.jackson to com.fasterxml.jackson[.core]
    • Some Maven artifact ids were also changed (like jackson-mapper-asl to jackson-databind), but that was optional cleanup; change of group id would have sufficed for isolation.

One thing that was done to simplify upgrade was to keep most public API type names unchanged -- specifically ObjectMapper and JsonFactory (as well as JsonParser, JsonGenerator) -- doing this meant that in many cases all that was needed was to mechanically change import statements and Maven pom.xml dependency declarations.

With 3.0 we are planning to do somewhat more aggressive class renaming, but keep some of most exposed names as-is (most specific example being JsonFactory / JsonParser / JsonGenerator set).

Potential avoidable problems

Although upgrade from Jackson 1 to Jackson 2 seemed to go largely well for most users (when they chose to do that), one somewhat painful and potentially unnecessary part was handling of annotations. Since annotations are type of metadata, and since changes between 1.9 and 2.0 were minimal, it was possible to create value classes (POJOs with no Jackson dependency exception for annotations) that worked with both Jackson 1.x and 2.x -- but if any annotations were required, both 1.x and 2.x annotations were needed as neither could read "other" annotations (note: it is actually possible to implement Jackson AnnotationIntrospector that DOES understand both -- and such implementations were written by 3rd party developers). But it seems that it might have been possible to handle annotation package compatibility different from other packages: we will extend on this in sections below, suggesting another way to tackle version evolution for annotations.

High-level Proposal

We should follow footsteps of Jackson-1-to-Jackson-2 upgrade in most parts, renaming Maven group-id (but none of artifact ids) as well as Java packages, but to keep many of existing high-level API type names unchanged (in cases where there is no important reasons for actually changing names -- for example, for reducing references to "json" for format-agnostic abstractions).

But one exception is that we should consider keeping jackson-annotations compatible across major versions. This would require keeping same Maven group and artifact ids, as well as Java package name. There are some trade-offs -- essentially, difference in versioning may seem confusing to users -- but there is some value in ability to use only a single set of annotations on (non-Jackson) POJOs, regardless of whether Jackson 2.x or 3.x is actually used for processing.

Proposal details

General naming

There is one general naming question to decide first: how to change Maven group id. Plan is to:

  • Change Maven group ids "com.fasterxml.jackson" -> "tools.jackson" (and same fur sub-groups)

tools.jackson domain is registered for this use.

Maven coordinates

We should consistently use the above translation, with the possible exception of jackson-annotations (see below).

We should keep existing artifact ids, unless there are particularly important reasons to change artifact-id. Currently none of the components is planned to be renamed.

Java packages

As with 2.x, I think we should use Maven group id, followed with (part of) artifact id as the root package name (omitting "jackson-" prefix from artifact id).

Handling of jackson-annotations

As indicated earlier, basic approach for all other components may not work as well for jackson-annotations. This because:

  1. Annotations are added as metadata on non-Jackson value types, and these should ideally be compatible across many Jackson versions (historically just across all 1.x or 2.x versions)
  2. Annotation evolution is slower, and so far they have been strictly backwards compatibility across both major versions -- unlike jackson-core, or, in particular jackson-databind. This means that keeping strict compatibility would likely be possible across (otherwise) major version boundary.

So. I propose we keep existing Maven id and Java package names for jackson-annotations (NOTE: we must keep both group and artifact ids) This would allow use of a single set of annotations during migration from 2.x to 3.x for processing; as well as exposing value libraries (by 3rd parties) that similarly work fine with both Jackson 2.x and Jackson 3.x

There are some challenges/downsides too:

  • Difference in Maven group id between annotations and other components can be confusing to users.
  • If we are to publish more 2.x versions, concurrently with 3.0 (a possibility but not certainty), we will probably need to be bit more careful in ensuring version compatibility (probably need to limit or even prevent changes in 2.x series after 2.19, to make 3.x annotations a strict superset of all 2.x annotations)

These do not seem too significant downsides to prevent taking this approach, but are worth considering.

Annotations versioning: drop patch version

Another related idea for 3.x annotations is to do something that has been planned for a while -- stop releasing patch versions. With Jackson 2.x, all patch versions are identical, and for example 2.9.0 and 2.9.5 have no differences. The reason we publish separate versions is simply because some users felt that doing this is simpler, and works better with existing tooling (such as Maven or Gradle plugins that verify consistent set of versions).

But with addition of jackson-bom with Jackson 2.8, there is now a better mechanism for getting compatible version sets; something where only single version is needed for reference.

So: part of versioning change is to start publishing jackson-annotations versions 3.0, 3.1 and so on; the only exception being if, for some reason, we absolutely have to make a patch release: if so, patch number will be used, but it does NOT have to match patch version of other components.

Clone this wiki locally