The default pool uses ThreadLocals, which aren't a great fit when using virtual threads.

See https://twitter.com/jkuipers/status/1762505881000808516

Comment From: mhalbritter

A lock free pool will be the default with Jackson 2.17: https://twitter.com/cowtowncoder/status/1762668711063003623

Comment From: jkuipers

Note that my original attempt to set this up had a bug, as you shouldn't share a single JsonFactory between different ObjectMappers created by the builder that we're customizing. Creating the factory within the customizer does the trick:

@Bean @ConditionalOnProperty(name = "spring.threads.virtual.enabled")
Jackson2ObjectMapperBuilderCustomizer loomCustomizer() {
    return builder -> {
        var jsonFactory = JsonFactory.builder().recyclerPool(JsonRecyclerPools.sharedLockFreePool()).build();
        builder.factory(jsonFactory);
    };
}

Comment From: mhalbritter

Thanks for the update!

Comment From: MazizEsa

@mhalbritter can I help out with this one? seems interesting.

Comment From: jkuipers

Or update straight to Jackson 2.17 where the default changed to a lock-free pool: you only need explicit configuration for 2.16.x. Older versions don’t support this.

Comment From: mhalbritter

Thanks @jkuipers. The update to Jackson has been done already in https://github.com/spring-projects/spring-boot/issues/39920, so this issue should be obsolete.

FTR, here's the issue on Jackson's side: https://github.com/FasterXML/jackson-core/issues/1117