Jackson 2.15 (v2.15.0-rc1 is out) has a default set of limits that it applies to inputs. Input Files that breach those limits will cause parse exceptions.

spring-boot will need to consider if those limits are ok or if you need to provide a way to configure the Jackson StreamReadConstraints.

https://javadoc.io/static/com.fasterxml.jackson.core/jackson-core/2.15.0-rc1/com/fasterxml/jackson/core/StreamReadConstraints.html

Comment From: wilkinsona

Thanks for raising this, @pjfanning.

At the ObjectMapper level, which is where Spring Boot operates, I can't quite see how to configure the constraints. As far as I can tell, they have to be configured on a JsonFactoryBuilder that's used to create a JsonFactory which is used in turn to create the ObjectMapper. That JsonFactory should be a MappingJsonFactory which, ideally, should be created with an ObjectMapper. I can't see how to create an ObjectMapper with a custom JsonFactory that itself has been created with that same ObjectMapper.

@cowtowncoder if you have a moment, could you please point us in the right direction here?

Comment From: pjfanning

Constructing a MappingJsonFactory from an existing ObjectMapper and then trying to override the StreamReadConstraints on the MappingJsonFactory - that is not currently allowed.

I'm not sure if this is something that jackson-databind should have but @cowtowncoder may see differently.

If there is no way for you to refactor your code, you could subclass jackson-databind's MappingJsonFactory and add a method to override the StreamReadConstraints.

Comment From: pjfanning

@wilkinsona could you highlight some code that you are worried about? I looked at spring-boot and all I can find is lots of code that uses new ObjectMapper().

Instead of new ObjectMapper(), you might find it a good idea to have a common ObjectMapperFactory, so that it easier to replace all the new ObjectMapper() calls with something like ObjectMapperFactory.createObjectMapper().

private static JsonFactory JSON_FACTORY;

// add some code to create JSON_FACTORY with your preferred StreamReadConstraints settings

public static createObjectMapper() {
   return JsonMapper.builder(JSON_FACTORY).build();
}

Comment From: wilkinsona

My concern is a general one and doesn't really focus on any specific area of Spring Boot's code. If there's a mechanism in Jackson for configuring the constraints then based on our past experience with configuring Jackson I expect that we'll be able to use it without too much difficulty. It's a configuration mechanism that's similar to what Jackson offers in various other areas that I am looking for.

If there is one area that's likely to be of specific concern it is in and around org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration. This auto-configuration applies the user's spring.jackson.* application properties and makes extensive use of Spring Framework's Jackson2ObjectMapperBuilder to do so. If the constraints need to be configurable, some new spring.jackson.* properties would be the obvious way for users to do so. I don't yet see how we could apply those properties to either a new or an existing ObjectMapper instance.

Comment From: pjfanning

Jackson is moving towards making Object Mappers immutable. You may need to rethink the idea of reconfiguring at that level. Factories and Builders are where Jackson config happens or that's where things are moving.

Comment From: cowtowncoder

Ok, while @pjfanning is correct in that we are moving to Builder-based configuration, there does need to be some support for old-style direct configuration for compatibility reasons. For new functionality this may not be needed but for StreamReadConstraints we do need something, I think. Jackson 3.x (only) will offer/require full immutability; before that there is just availability of Builders with only partial benefits.

I will file a jackson-core issue to make sure there is actually a way to directly set configuration via JsonFactory -- I do believe that it is impractical to expect frameworks to switch to Builder-style construction (and more importantly, exposing that to their users) mid-Jackson-2.x

EDIT: created https://github.com/FasterXML/jackson-core/issues/962

Thank you @pjfanning for due diligency here: I think this is something that must be resolved for 2.15.0 final & is a good catch now (instead of after release).

Comment From: cowtowncoder

@wilkinsona I did add the obvious 2.x, non-builder mechanism (see https://github.com/FasterXML/jackson-core/issues/962), that is, JsonFactory.setStreamReadConstraints(). It will be in 2.15.0-rc2. Thank you for outlining this obvious (in hindsight, although I really should have seen it ahead of time too) gap.

As usual, help by Spring Boot team is much appreciated: as much as I want 2.15.0 to get done ASAP, I want to also avoid rushing and breaking existing usage by valued user communities.

Comment From: wilkinsona

Thanks very much, @cowtowncoder.

Comment From: wilkinsona

With the new setter, it'll be possible for someone to configure the constraints in a Spring Boot application without requiring any changes in Boot:

@Bean
Jackson2ObjectMapperBuilderCustomizer customStreamReadConstraints() {
    return (builder) -> builder.postConfigurer((objectMapper) -> objectMapper.getFactory()
        .setStreamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(2000).build()));
}

This will ensure that any ObjectMapper created through the auto-configured Jackson2ObjectMapperBuilder will have a max nesting depth of 2000. We can still consider adding some configuration properties for the three constraints if tuning them is a common requirement.

Comment From: cowtowncoder

Correct @wilkinsona, that's the idea.

Comment From: jamesdh

We've added a Jackson2ObjectMapperBuilderCustomizer to modify the max string length like @wilkinsona mentioned but we're not seeing this reflected in our tests that use an injected ObjectMapper. We've also tried using StreamReadConstraints.overrideDefaultStreamReadConstraints to force override at application startup, but again, no luck. Still hitting the 20,000,000 limit.

@Configuration
public class JacksonConfig {
    @Bean
    Jackson2ObjectMapperBuilderCustomizer customStreamReadConstraints() {
        return (builder) -> builder.postConfigurer((objectMapper) -> objectMapper.getFactory()
            .setStreamReadConstraints(StreamReadConstraints.builder().maxStringLength(100000000).build()));
    }
}
public static void main(String[] args) {
    StreamReadConstraints.overrideDefaultStreamReadConstraints(
        StreamReadConstraints.builder().maxStringLength(100000000).build()
    );
    SpringApplication.run(ApiApplication.class, args);
}

Comment From: jamesdh

The only way I could get this to work was to override the defaults in a static context, e.g.

@Configuration
public class JacksonConfig {
    static {
        StreamReadConstraints.overrideDefaultStreamReadConstraints(
            StreamReadConstraints.builder().maxStringLength(100000000).build()
        );
    }
}

**Comment From: wilkinsona**

@jamesdh I can't reproduce the behaviour you've described in either case. If `overrideDefaultStreamReadConstraints` is not working, it sounds like something else is configuring the constraints and preventing the overridden defaults from taking effect. Please follow up with a question on Stack Overflow that includes a minimal example that reproduces the problem.

**Comment From: jamesdh**

@wilkinsona I got `overrideDefaultStreamReadConstraints` working but had to call it from a static context. I guess that implies some other bean/config in a 3rd party dependency could be at cause? We have nothing else in our code that touches  the ObjectMapper config. 

**Comment From: wilkinsona**

It's really a Jackson question, but as far as I know changes to the defaults should affect every `com.fasterxml.jackson.core.JsonFactory` that's created thereafter. As I said above, please follow up on Stack Overflow as this issue isn't that right place for this.

**Comment From: cowtowncoder**

I think this issue should be closed as the original change was done.

And if there are follow-up issues, file issue in appropriate place(s).


**Comment From: wilkinsona**

I'd like to keep the issue open to see if there's sufficient interest in some `spring.jackson.*` configuration properties for configuring the constraints. In the meantime, using a customizer or an early call to `StreamReadConstraints.overrideDefaultStreamReadConstraints` remains the recommended approach.

**Comment From: jjstreet**

We just ran into this situation. Received a constraints limit reached. It would be nice to be able to set this via properties as most of the configuration we do is via those properties.

**Comment From: cowtowncoder**

Jackson does not offer much any global configutation, by design -- it is typically embedded as a component so global configuration tends to break usage in unintended places.

So no support for property configuration will be added on Jackson side.

**EDIT**: please disregard, as per @wilkinsona comment I was confused about question; not related to Jackson side. Spring definitely has lots of relevant configurability.


**Comment From: wilkinsona**

@cowtowncoder, I assume @jjstreet was referring to Spring Boot properties. We already [provide several for configuring an `ObjectMapper` instance](https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.json.spring.jackson.constructor-detector) and could add to them to provide property-based configuration for its stream read constraints.

**Comment From: cowtowncoder**

@wilkinsona Thank you for pointing this out -- yeah I should pay attention to where issue exists, not just look at title & update :)


**Comment From: gyula-lakatos**

> @cowtowncoder, I assume @jjstreet was referring to Spring Boot properties. We already [provide several for configuring an `ObjectMapper` instance](https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.json.spring.jackson.constructor-detector) and could add to them to provide property-based configuration for its stream read constraints.

It would be quite useful. I keep hitting certain limits every now and then. Copying the same configuration class to every microservice is quite suboptimal. Releasing a jar that has the ability to enable the configuration via properties and including it as a dependency in every app is even more problematic.

**Comment From: jjstreet**

I will say that we were able to route around the stream limit constraints by using the suggested customizer class.

Where would such a property exist? `spring.jackson.deserialization.*`?

**Comment From: wilkinsona**

I'm not sure but it couldn't be a `spring.jackson.deserialization` property as they're a `Map<DeserializationFeature, Boolean>`. We'll have to give it some thought.

**Comment From: smarbl-AmitRohra**

> The only way I could get this to work was to override the defaults in a static context, e.g.
> 
> ```java
> @Configuration
> public class JacksonConfig {
>     static {
>         StreamReadConstraints.overrideDefaultStreamReadConstraints(
>             StreamReadConstraints.builder().maxStringLength(100000000).build()
>         );
>     }
> }
> ```

This works to allow larger string/json as input 

**Comment From: rgambelli**

Hi all, so for what I'm understanding, me that having many springboot 3.2.x so with jackson 2.15.4, there is no spring.jackson property currently available to increase that limit of 20MB? I've reached that limit with some email for that I need to post its content.

So the only solution is to modify the ObjectMapper? Thank you for the confirmation

**Comment From: nosan**

Hi @rgambelli 

> So the only solution is to modify the ObjectMapper? Thank you for the confirmation

Yes

>there is no spring.jackson property currently available to increase that limit of 20MB?

There is no `spring.jackson.*` properties at the moment to configure `StreamReadConstraints`.


--- 
You can use the following configuration to modify `StreamReadConstraints`.

```java

import com.fasterxml.jackson.core.StreamReadConstraints;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class JacksonConfiguration {

    @Bean
    Jackson2ObjectMapperBuilderCustomizer streamReadConstaintsCustomizer() {
        return (builder) -> builder.postConfigurer((objectMapper) -> objectMapper.getFactory()
                .setStreamReadConstraints(StreamReadConstraints.defaults()
                        .rebuild()
                        .maxDocumentLength()
                        .maxStringLength()
                        .maxNameLength()
                        .maxNestingDepth()
                        .maxTokenCount()
                        .build()));
    }

}

}

Comment From: rgambelli

Sorry @nosan I'm trying with your class, I can confirm debugging that the flow goes through that builder but the issue is not fixed.

In this screenshot you can see the org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter class and as you can see the default objectmapper is selected nevertheless its stream read constraints are not changed according to the configuration.

I'm using springboot 3.2.4, thanks for your help

Image

Comment From: pjfanning

I don't understand the StreamReadConstraints that @nosan 's example creates. It appears to create a default constraints instance with the default limits. These default limits can be too low.

Comment From: nosan

@rgambelli

I've tested the StreamReadConstraints customizer with a small application, and everything works as expected.

The sample application can be downloaded using this link: gh-34709.zip

 :: Spring Boot ::                (v3.2.4)
2025-03-26T20:31:13.770+02:00  INFO 75386 --- [gh-34709] [    Test worker] task.gh34709.Gh34709ApplicationTest      : Starting Gh34709ApplicationTest using Java 17.0.13 with PID 75386 (started by dmytronosan in /Users/dmytronosan/IdeaProjects/gh-34709)
2025-03-26T20:31:13.770+02:00  INFO 75386 --- [gh-34709] [    Test worker] task.gh34709.Gh34709ApplicationTest      : No active profile set, falling back to 1 default profile: "default"
2025-03-26T20:31:14.086+02:00  INFO 75386 --- [gh-34709] [    Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 0 (http)
2025-03-26T20:31:14.091+02:00  INFO 75386 --- [gh-34709] [    Test worker] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-03-26T20:31:14.091+02:00  INFO 75386 --- [gh-34709] [    Test worker] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.19]
2025-03-26T20:31:14.116+02:00  INFO 75386 --- [gh-34709] [    Test worker] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-03-26T20:31:14.116+02:00  INFO 75386 --- [gh-34709] [    Test worker] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 339 ms
2025-03-26T20:31:14.241+02:00  INFO 75386 --- [gh-34709] [    Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 58741 (http) with context path ''
2025-03-26T20:31:14.245+02:00  INFO 75386 --- [gh-34709] [    Test worker] task.gh34709.Gh34709ApplicationTest      : Started Gh34709ApplicationTest in 0.565 seconds (process running for 0.955)
2025-03-26T20:31:14.650+02:00  INFO 75386 --- [gh-34709] [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-03-26T20:31:14.650+02:00  INFO 75386 --- [gh-34709] [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-03-26T20:31:14.651+02:00  INFO 75386 --- [gh-34709] [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

2025-03-26T20:31:14.670+02:00  WARN 75386 --- [gh-34709] [o-auto-1-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Depth (65) exceeds the maximum allowed nesting depth (64)] 

Comment From: nosan

I don't understand the StreamReadConstraints that @nosan 's example creates. It appears to create a default constraints instance with the default limits. These default limits can be too low.

The code snippet I provided does not compile as it is, and appropriate values need to be supplied by a developer.