Skip to content
JSBlogs
Go back

Fine-grained Jackson configuration in Spring Boot 4.1

Jackson is the default JSON library in almost every Spring Boot application, but tuning it precisely has always required more effort than it should. Spring Boot 4.1 introduces separate spring.jackson.read.* and spring.jackson.write.* property namespaces so you can control deserialization and serialization independently — without writing a single line of Java configuration.

Table of contents

Open Table of contents

The problem with older versions (Spring Boot 3.x and earlier)

Spring Boot has long exposed some Jackson properties, but the coverage was uneven and the separation between reading and writing was blurry.

Limited built-in properties

Spring Boot 3.x exposed a flat set of Jackson settings: date format, property naming strategy, visibility, and a handful of serialization features. For anything else, you were on your own.

# Spring Boot 3.x - fine for basics
spring.jackson.serialization.write-dates-as-timestamps=false
spring.jackson.deserialization.fail-on-unknown-properties=false
spring.jackson.default-property-inclusion=non_null

That worked for common cases, but there was no systematic way to configure the full range of SerializationFeature and DeserializationFeature flags.

Java-based ObjectMapper customization scattered config

When teams needed more control, the usual answer was a @Bean to customize ObjectMapper:

@Configuration
class JacksonConfig {

    @Bean
    Jackson2ObjectMapperBuilderCustomizer customizer() {
        return builder -> builder
                .featuresToEnable(SerializationFeature.INDENT_OUTPUT)
                .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
                .featuresToEnable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
    }
}

This worked, but it split Jackson configuration between application.properties and Java code, making it harder to audit behavior in one place.

Read and write settings were conflated

There was no clean way to say “only when deserializing” vs “only when serializing.” Many settings were global, and toggling them for one direction often had unintended effects on the other.

Important: When Jackson configuration is split across properties files and multiple Java beans, tracking down unexpected serialization behavior during debugging takes much longer than it should.

What Spring Boot 4.1 changes

Spring Boot 4.1 introduces two new property namespaces that map directly to Jackson’s DeserializationFeature and SerializationFeature enums.

Configure deserialization precisely

Control how Jackson reads JSON without touching Java code.

# Fail if an unknown field arrives — catch schema drift early
spring.jackson.read.fail-on-unknown-properties=true

# Be lenient with single-value arrays
spring.jackson.read.accept-single-value-as-array=true

# Do not adjust dates to the local timezone on read
spring.jackson.read.adjust-dates-to-context-time-zone=false

Configure serialization precisely

Control how Jackson writes JSON, separately from reading behavior.

# Pretty-print JSON in development environments
spring.jackson.write.indent-output=true

# Do not serialize dates as numeric timestamps
spring.jackson.write.write-dates-as-timestamps=false

# Omit null values from output
spring.jackson.write.write-null-map-values=false

Combine both in one place

Both namespaces live side by side in application.properties or application.yaml. No Java required for most use cases.

spring:
  jackson:
    default-property-inclusion: non_null
    read:
      fail-on-unknown-properties: true
      accept-single-value-as-array: true
    write:
      indent-output: false
      write-dates-as-timestamps: false

Tip: Use environment-specific property files to vary Jackson settings. For example, enable write.indent-output=true in application-dev.properties for readable payloads during local development, and keep it off in production.

Old way vs new way

AreaOlder versionsSpring Boot 4.1
Deserialization controlLimited properties + Java configspring.jackson.read.* namespace
Serialization controlLimited properties + Java configspring.jackson.write.* namespace
Config locationSplit between properties and beansAll in properties/yaml
Clarity on read vs writeMixed togetherSeparate namespaces

Practical tips for rollout

  1. Audit your existing Jackson2ObjectMapperBuilderCustomizer beans and move every flag that has a matching property to application.properties.
  2. Use spring.jackson.read.fail-on-unknown-properties=true in staging to catch schema drift early.
  3. Set per-environment write.indent-output rather than toggling it in code.
  4. Check the full list of supported flags in the Spring Boot 4.1 reference documentation — the coverage is significantly wider than 3.x.

Caution: If you set a feature in both application.properties and a Java customizer bean, the bean takes precedence. After migrating, remove the Java config entry to avoid confusion about which value is active.

Migration checklist from older projects

  1. Open each Jackson2ObjectMapperBuilderCustomizer or ObjectMapper bean in the project.
  2. List every featuresToEnable() and featuresToDisable() call.
  3. For each flag, check whether a matching spring.jackson.read.* or spring.jackson.write.* property exists in Spring Boot 4.1 docs.
  4. Move those flags to application.properties and delete the corresponding Java line.
  5. If the Java bean becomes empty after migrating all flags, delete the bean class entirely.
  6. Run a serialization round-trip test to confirm JSON output is unchanged.

Note: Centralizing Jackson config in properties makes behavior auditable, but it does not replace deliberate API design. Clear field names, consistent date formats, and stable schema are still the most important part of a good JSON contract.

References


Share this post on:

Previous Post
Async context propagation improvements in Spring Boot 4.1
Next Post
JmsClient in Spring Boot 4.x for cleaner messaging code