Skip to content

JsonMapper.Builder cannot be auto-configured with a custom JsonFactory #48594

@mhewedy

Description

@mhewedy

Background

With the migration to Jackson 3.0 in Spring Boot 4, the JsonMapper.Builder has become the primary way to configure the mapper. Unlike Jackson 2.x, Jackson 3.0 emphasizes immutability; specifically, the TokenStreamFactory (e.g., JsonFactory) must be provided at the time the Builder is instantiated.

Current Behavior
In JacksonAutoConfiguration, the JsonMapper.Builder bean is currently initialized using the no-args constructor:

// JacksonAutoConfiguration.java
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnMissingBean
JsonMapper.Builder jsonMapperBuilder(List<JsonMapperBuilderCustomizer> customizers) {
    JsonMapper.Builder builder = JsonMapper.builder(); // Uses default JsonFactory
    customize(builder, customizers);
    return builder;
}

The Problem
Because JsonMapper.builder() is hardcoded to use a default factory, there is no way to provide a custom JsonFactory (configured with CharacterEscapes for XSS protection, for example) without overriding the entire JsonMapper.Builder bean.

Overriding the builder bean is high-friction because it requires the developer to manually replicate the logic that applies the List<JsonMapperBuilderCustomizer>, effectively "detaching" from the standard Spring Boot auto-configuration flow just to change a low-level factory setting.

Proposed Solution
Extract the JsonFactory into its own @Bean and inject it into the builder. This allows users to simply override the JsonFactory bean while keeping the rest of the auto-configuration intact.

@Bean
@ConditionalOnMissingBean
JsonFactory jsonFactory() {
    return JsonFactory.builder().build();
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnMissingBean
JsonMapper.Builder jsonMapperBuilder(JsonFactory jsonFactory, List<JsonMapperBuilderCustomizer> customizers) {
    // Injecting the factory into the builder at construction time
    JsonMapper.Builder builder = JsonMapper.builder(jsonFactory);
    customize(builder, customizers);
    return builder;
}

This change would significantly improve extensibility for security-focused configurations (like CharacterEscapes) in the Jackson 3.0 ecosystem.

I can submit a PR

Metadata

Metadata

Assignees

Labels

for: team-meetingAn issue we'd like to discuss as a team to make progresstype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions