JSTEP 2 - FasterXML/jackson-future-ideas GitHub Wiki

(Back to JSTEP page)


Jackson 3 default settings, behavior changes

Author

Tatu Saloranta (@cowtowncoder), Joo Hyuk Kim (@JooHyukKim)

Version history

  • 2026-08-09: Add rationale for default changes from future-ideas#107, document MapperFeature.DETECT_PARAMETER_NAMES, correct StreamWriteFeature.USE_FAST_DOUBLE_WRITER status - @JooHyukKim
  • 2025-10-11: Add TokenStreamFactory.Feature.INTERN_PROPERTY_NAMES
  • 2025-08-27: Some notes on Date/Time handling changes.
  • 2025-07-24: Update wrt revert of default change for JsonWriteFeature.ESCAPE_FORWARD_SLASHES default
  • 2025-05-12: Update wrt CBOR read/write feature defaults - @cowtowncoder
  • 2025-05-05: Update wrt DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES revert - @cowtowncoder
  • 2025-05-03: Update wrt MonthSerializer and MonthDeserializer behavior change - @JooHyukKim
  • 2025-04-08: Added DateTimeFeature.ONE_BASED_MONTHS - @cowtowncoder
  • 2025-04-06: Added MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS - @cowtowncoder
  • 2025-02-05: Updates wrt XmlWriteFeature default changes - @cowtowncoder
  • 2025-02-01: Update wrt SerializationFeature.WRITE_DATES_AS_TIMESTAMPS default change - @cowtowncoder
  • 2025-01-31: Update wrt SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS default change - @cowtowncoder
  • 2025-01-29: Update wrt DeserializationFeature.FAIL_ON_TRAILING_TOKENS default change - @cowtowncoder
  • 2025-01-19: Add Kotlin module proposed change links - @cowtowncoder
  • 2024-07-21: DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES default changed - @cowtowncoder
  • 2024-06-06: DeserializationFeature.READ_ENUMS_USING_TO_STRING, SerializationFeature.WRITE_ENUMS_USING_TO_STRING defaults changed - @cowtowncoder
  • 2024-05-31: MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS default changed - @cowtowncoder
  • 2019-02-10: create first version from earlier notes - @cowtowncoder

Status

Complete as of 3.0.0 release.

Overview

During Jackson 2.x development, certain default settings have proven either problematic by development team, or non-intuitive/non-optimal by users: latter indicated both by filed issues and comments on mailing list discussions. Since default settings and behavior are important part of the public API, changes have had to wait until major version change in most cases.

This document details proposed/planned as well as implemented changes.

Changes to jackson-core defaults

JsonReadFeature

No changes

JsonWriteFeature

No changes

  • NOTE: initially planned change to JsonWriteFeature.ESCAPE_FORWARD_SLASHES defaults were rolled back in 3.0.0-rc7

StreamReadConstraints

  • DEFAULT_MAX_DEPTH to 500 (from 1,000) (see core#1233)
    • Rationale: the old limit was high enough that deeply nested fuzz/adversarial input could still hit a JVM StackOverflowError before Jackson's guard triggered. 500 remains well above expected real-world document depth, while staying below the observed stack-overflow zone.

StreamWriteConstraints

  • DEFAULT_MAX_DEPTH to 500 (from 1,000) (see core#1233)
    • Rationale: same as StreamReadConstraints.DEFAULT_MAX_DEPTH; the limit should protect Jackson before native stack depth becomes the failure mode, without affecting legitimate content.

StreamReadFeature

  • USE_FAST_DOUBLE_PARSER: enabled by default in 3.0 (see core#1231)
  • USE_FAST_BIG_NUMBER_PARSER: enabled by default in 3.0 (see core#1231)
    • Rationale: the faster number parsers were introduced as opt-in in Jackson 2.14 to reduce compatibility risk. After a long opt-in period without correctness reports, enabling them by default in the major-version boundary was considered reasonable for better out-of-the-box number parsing performance.

StreamWriteFeature

  • USE_FAST_DOUBLE_WRITER: default unchanged -- remains disabled in 3.0 (see core#1231, source)
    • Rationale: a writer-side default flip was considered, but rejected because newer JDKs already provide equivalent or better double-to-string handling. The feature remains opt-in, primarily useful for older supported JDKs.

TokenStreamFactory.Feature

  • INTERN_PROPERTY_NAMES: disabled by default in 3.0 (see core#378)
    • Rationale: interning property names used to speed databind property matching through identity checks, but it had memory-management costs for high-cardinality names and no benefit for streaming-only usage. Jackson 3's FieldNameMatcher / nextFieldName(...) path removes the old need for interning while preserving or improving databind performance.

Changes to jackson-databind defaults

MapperFeature

First, following deprecated features have been removed from 3.0:

  • USE_STD_BEAN_NAMING: should always be enabled, no need for old slightly differing algorithm
  • AUTO_DETECT_xxx: old limited settings superseded by more granular settings -- frees up 5 features
    • AUTO_DETECT_CREATORS
    • AUTO_DETECT_FIELDS
    • AUTO_DETECT_GETTERS
    • AUTO_DETECT_IS_GETTERS
    • AUTO_DETECT_SETTERS

And defaults to following features have been changed:

  • ALLOW_FINAL_FIELDS_AS_MUTATORS: default to false -- while enabling may be useful sometimes, it confuses users in general and is unlikely to even work with future JDKs/JVMs
  • DETECT_PARAMETER_NAMES: default to true
    • Rationale: Jackson 3 integrates the Jackson 2.x jackson-parameter-names module functionality into databind and enables it by default. This lets constructor and factory method parameter names be used as implicit names, avoiding extra @JsonProperty annotations when classes are compiled with -parameters.
    • Compatibility note: this may affect creator auto-detection and creator-property ordering compared with a Jackson 2.x mapper that did not register jackson-parameter-names. MapperBuilder.configureForJackson2() disables this feature for Jackson 2.x-compatible defaults.
    • databind#5314
  • DEFAULT_VIEW_INCLUSION: default to false: has been requested by users and change initially approved
    • Rationale: the 2.x default made unannotated properties included even when a view was active, which made @JsonView closer to opt-out behavior. false makes active views work like an explicit allow-list of view-annotated properties, matching what Spring and many users already expected.
    • Performance note: maintainers re-ran benchmark combinations before merging and no longer considered the overhead meaningful enough to block the change.
    • databind#1484
  • USE_GETTERS_AS_SETTERS: default to false -- earlier default was based on JAXB but is quite confusing for users
  • SORT_PROPERTIES_ALPHABETICALLY: default to true (false really doesn't make much sense since it is unstable, and arbitrary based on JVM/JDK)

Changes, potential:

  • OVERRIDE_PUBLIC_ACCESS_MODIFIERS: potential default to false, since benefits of enabling seem small if not non-existent with 3.0
    • Rationale: forced setAccessible(true) for already-public members was historically a reflection performance optimization, but that benefit becomes weaker if access paths move toward MethodHandles; keeping it enabled also increases the surface for JPMS / restricted-access failures.
    • Status: not changed for 3.0; databind#5074 remains open and the source still has this feature enabled by default as of current 3.x.
    • databind#5074

DeserializationFeature

Changes completed:

  • FAIL_ON_UNKNOWN_PROPERTIES: default to false (TOP REQUEST by users) databind#493
    • Rationale: JSON producers and consumers often evolve independently. Failing on every unknown field makes compatible schema growth brittle, whereas skipping unknown values follows the open-content/forward-compatibility model requested by many users and used by comparable frameworks. A DoS concern was discussed and not considered practical because unknown values are skipped from the streaming parser, not materialized as trees.
  • READ_ENUMS_USING_TO_STRING: default to true (instead of false that relies on name()) databind#4566
    • Rationale: for ordinary enums the result is the same because Enum.toString() defaults to name(), but name() is final while toString() can be overridden. This gives enum types a natural annotation-free customization hook and was requested by multiple users (see maintainer comment).
    • Compatibility note: enums whose toString() differs from name() will change their JSON representation unless the mapper is configured back to Jackson 2.x behavior. java.time.temporal.ChronoUnit was reported as one such affected JDK enum.
    • NOTE: this was further renamed/moved as EnumFeature.READ_ENUMS_USING_TO_STRING (via databind#5079)
  • FAIL_ON_NULL_FOR_PRIMITIVES: default to true (databind#4858)
    • Setting to false would allowing coercion from JSON null into Java int, long and so on. For some users, and especially on "low null" languages like Kotlin, such coercion is rarely expected.
  • FAIL_ON_TRAILING_TOKENS: default to true (databind#3406)
    • Rationale: with the 2.x default, readValue() could successfully read the first value and silently ignore extra content after it. Failing by default catches malformed garbage, accidentally concatenated documents, and parsing-differential risks; enabling it during 3.0 work also exposed real backend regressions.
    • Compatibility note: callers intentionally doing partial/streaming reads may need to disable this feature.

Changes planned but not made (or were reverted):

SerializationFeature

Changes completed:

  • WRITE_ENUMS_USING_TO_STRING: default to true (to keep symmetry between its DeserializationFeature.READ_ENUMS_USING_TO_STRING counterpart) databind#4567
    • Rationale: same enum rationale as READ_ENUMS_USING_TO_STRING: toString() preserves the default representation for vanilla enums while allowing custom enum wire names through an overridable method.
    • NOTE: this was further renamed/moved as EnumFeature.WRITE_ENUMS_USING_TO_STRING (via databind#5080)
  • FAIL_ON_EMPTY_BEANS: default to false databind#3070
    • Rationale: an object with no visible properties has a clear JSON representation, {}. Treating it as an exception surprised users and could obscure the real failure path in frameworks; users who want the old fail-fast diagnostic can explicitly re-enable the feature.
  • FAIL_ON_ORDER_MAP_BY_INCOMPARABLE_KEY : was added in 2.19. Changed default in 3.0 via databind#4781
    • Rationale: when key ordering is requested, sorting via TreeMap can fail for non-Comparable keys. Jackson 3 defaults this new guard to false, so incomparable-key maps fall back to original map iteration order instead of hard-failing, while callers who want the diagnostic exception can enable it.
    • See also databind#4773.
  • WRITE_DURATIONS_AS_TIMESTAMPS: change default to false to serialize as ISO-8601 String -- databind#4846
    • Rationale: numeric duration/period output is compact, but users and frameworks generally expect textual ISO-8601 duration representations by default. The major-version boundary allows Jackson to prefer the more interoperable human-readable shape.
    • Note: renamed/moved as DateTimeFeature.WRITE_DURATIONS_AS_TIMESTAMPS
  • Writing date/time values as ISO-8601 Strings instead of (Java style) timestamps
    • WRITE_DATES_AS_TIMESTAMPS: change default to false to serialize as ISO-8601 String -- databind#4845
      • Rationale: numeric date/time timestamps are efficient, but the issues note that most users and frameworks expect strings. Jackson 3 therefore defaults to textual ISO-8601 output for date/time values.
      • Note: renamed/moved as DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS
    • WRITE_DATE_KEYS_AS_TIMESTAMPS: RETAIN default of false -- no change
      • Note: renamed/moved as DateTimeFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS

DateTimeFeature

Changes completed:

  • ONE_BASED_MONTHS: default to true (3.0.0-rc3)
    • Rationale: this affects numeric handling of java.time.Month. The Jackson 2.x zero-based behavior was retained for backwards compatibility, but it conflicts with Month.getValue(), ISO-8601, and ordinary calendar convention; Jackson 3 changes numeric month values to one-based by default.
    • MapperBuilder.configureForJackson2() sets this back to false for Jackson 2.x compatibility.
    • https://github.com/FasterXML/jackson-databind/issues/5065
  • Moved entries from DeserializationFeature: ADJUST_DATES_TO_CONTEXT_TIME_ZONE, READ_DATE_TIMESTAMPS_AS_NANOSECONDS
  • Moved entries from SerializationFeature (WRITE_DATE_xxx and similar)

Changes to other format backend defaults

Changes to CBOR defaults

  • CBORReadFeature:
    • CBORReadFeature.DECODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING: change default to true CBOR#582
      • Rationale: Jackson 2.x kept its legacy negative BigInteger encoding for compatibility, but that encoding is not the standard CBOR representation. Jackson 3 enables standard decoding by default for interoperability with spec-compliant CBOR implementations.
    • CBORReadFeature.READ_UNDEFINED_AS_EMBEDDED_OBJECT: change default to true CBOR#591
      • Rationale: when disabled, CBOR undefined is exposed as JsonToken.VALUE_NULL, making it indistinguishable from a real CBOR null. Jackson 3 exposes it as VALUE_EMBEDDED_OBJECT with embedded value null, preserving the wire-level distinction.
    • CBORReadFeature.READ_SIMPLE_VALUE_AS_EMBEDDED_OBJECT: change default to true CBOR#591
      • Rationale: when disabled, generic CBOR simple values are exposed as integer tokens, which makes them look like ordinary numbers. Jackson 3 exposes them as VALUE_EMBEDDED_OBJECT values backed by CBORSimpleValue, so callers can distinguish them from real integers.
  • CBORWriteFeature:
    • CBORWriteFeature.ENCODE_USING_STANDARD_NEGATIVE_BIGINT_ENCODING: change default to true CBOR#582
      • Rationale: same interoperability reason as read-side negative BigInteger handling; Jackson 3 writes the standard CBOR representation by default instead of the legacy Jackson encoding.

Changes to XML defaults

  • XmlWriteFeature
    • XmlWriteFeature.UNWRAP_ROOT_OBJECT_NODE: Change default to true XML#725
      • Rationale: for a root ObjectNode with exactly one entry, using that entry's key as the root element name produces the expected XML root instead of a generic wrapper name.
    • XmlWriteFeature.WRITE_NULLS_AS_XSI_NIL: Change default to true XML#727
      • Rationale: XML Schema defines xsi:nil for null-valued elements; enabling this makes null output explicit instead of relying on an ambiguous empty element.
    • XmlWriteFeature.AUTO_DETECT_XSI_TYPE: Change default to true XML#728
      • Rationale: polymorphic XML type ids often need the standard xsi:type attribute, and this feature automatically maps logical property name xsi:type to the proper XML Schema Instance namespace.
    • XmlWriteFeature.WRITE_XML_SCHEMA_CONFORMING_FLOATS: Change default to true XML#729
      • Rationale: XML Schema and JAXB use INF / -INF for infinity values, while Java's Infinity / -Infinity strings are not understood by XML Schema-conforming readers.

Changes to Date/Time defaults

NOTE: see above for databind DateTimeFeature changes (including replacing some SerializationFeature/DeserializationFeatures), as well as default setting changes:

Changes to defaults, handling:

  • The default rendering for UTC in 3.0 is now a trailing Z, not a +00 as in 2.x.
    • Implementation note: current 3.x has DateTimeFeature.WRITE_UTC_AS_OFFSET, disabled by default, to represent the Jackson 3 behavior; MapperBuilder.configureForJackson2() enables it for 2.x-compatible mapper defaults.

Proposed (but not completed) changes:

  • Disable lenient setting (that is: default to "strict")

Changes to jackson-module-kotlin defaults

Kotlin module has a few proposed/accepted changes.

Misc other default setting, behavior changes

JsonNode handling

  • DecimalNode creation via JsonNodeFactory: default to NOT truncating trailing zeroes (minimal trimming), because JsonNode should by default expose content as close to way it came.

MonthSerializer and MonthDeserializer behavior change (databind#5127)

  • In 2.x, java.time.Month was handled as plain Enum and was applied with Enum-related handling such as EnumFeature.WRITE_ENUMS_USING_INDEX or EnumFeature.WRITE_ENUMS_USING_TO_STRING.
  • Starting 3.x, along with java-time merging to databind module, it's now handled like regular date/time classes, defaulting to number as value.
    • Note: numeric Month values are affected by DateTimeFeature.ONE_BASED_MONTHS; Jackson 3 defaults to one-based month numbers.

Using Jackson 2.x defaults in Jackson 3

For projects that still rely on Jackson 2.x behavior, Jackson 3 provides a builder method that configures an ObjectMapper with the older defaults where possible.

To create an ObjectMapper using Jackson 2.x defaults:

ObjectMapper mapper = JsonMapper.builderWithJackson2Defaults().build();

Note: This method does not (and cannot) fully replicate every Jackson 2.x default. Verify behavior in your application before relying on it.