Isolate Jackson2ObjectMapperBuilder mutation
Previously, Jackson2ObjectMapperBuilder was a singleton bean. This meant that if it was injected and mutated in one injection point, usage in a subsequent injection point would see the previous injection point's mutation which can lead to unexpected failures. This commit updates the auto-configuration of the builder to make it a protoype bean. Mutation of the builder that is intended to apply globally should be made using a customizer. Closes gh-17477
This commit is contained in:
parent
c7d2799f4e
commit
ea1dc85d50
|
|
@ -54,6 +54,7 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -168,6 +169,7 @@ public class JacksonAutoConfiguration {
|
|||
static class JacksonObjectMapperBuilderConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
@ConditionalOnMissingBean
|
||||
Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,
|
||||
List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
|
||||
|
|
|
|||
|
|
@ -391,6 +391,16 @@ class JacksonAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderIsNotSharedAcrossMultipleInjectionPoints() {
|
||||
this.contextRunner.withUserConfiguration(ObjectMapperBuilderConsumerConfig.class).run((context) -> {
|
||||
ObjectMapperBuilderConsumerConfig consumer = context.getBean(ObjectMapperBuilderConsumerConfig.class);
|
||||
assertThat(consumer.builderOne).isNotNull();
|
||||
assertThat(consumer.builderTwo).isNotNull();
|
||||
assertThat(consumer.builderOne).isNotSameAs(consumer.builderTwo);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class<?>... configClasses) {
|
||||
this.contextRunner.withUserConfiguration(configClasses).run((context) -> {
|
||||
DeserializationConfig deserializationConfig = context.getBean(ObjectMapper.class)
|
||||
|
|
@ -479,6 +489,27 @@ class JacksonAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ObjectMapperBuilderConsumerConfig {
|
||||
|
||||
Jackson2ObjectMapperBuilder builderOne;
|
||||
|
||||
Jackson2ObjectMapperBuilder builderTwo;
|
||||
|
||||
@Bean
|
||||
String consumerOne(Jackson2ObjectMapperBuilder builder) {
|
||||
this.builderOne = builder;
|
||||
return "one";
|
||||
}
|
||||
|
||||
@Bean
|
||||
String consumerTwo(Jackson2ObjectMapperBuilder builder) {
|
||||
this.builderTwo = builder;
|
||||
return "two";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static final class Foo {
|
||||
|
||||
private String name;
|
||||
|
|
|
|||
Loading…
Reference in New Issue