Inject Jackson modules rather than retrieving them manually

Fixes gh-32863
This commit is contained in:
Andy Wilkinson 2022-10-27 13:35:37 +01:00
parent 65c68ba64e
commit b9e176ce1a
2 changed files with 38 additions and 15 deletions

View File

@ -38,8 +38,7 @@ import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -171,21 +170,21 @@ public class JacksonAutoConfiguration {
@Bean
StandardJackson2ObjectMapperBuilderCustomizer standardJacksonObjectMapperBuilderCustomizer(
ApplicationContext applicationContext, JacksonProperties jacksonProperties) {
return new StandardJackson2ObjectMapperBuilderCustomizer(applicationContext, jacksonProperties);
JacksonProperties jacksonProperties, ObjectProvider<Module> modules) {
return new StandardJackson2ObjectMapperBuilderCustomizer(jacksonProperties, modules.stream().toList());
}
static final class StandardJackson2ObjectMapperBuilderCustomizer
implements Jackson2ObjectMapperBuilderCustomizer, Ordered {
private final ApplicationContext applicationContext;
private final JacksonProperties jacksonProperties;
StandardJackson2ObjectMapperBuilderCustomizer(ApplicationContext applicationContext,
JacksonProperties jacksonProperties) {
this.applicationContext = applicationContext;
private final Collection<Module> modules;
StandardJackson2ObjectMapperBuilderCustomizer(JacksonProperties jacksonProperties,
Collection<Module> modules) {
this.jacksonProperties = jacksonProperties;
this.modules = modules;
}
@Override
@ -305,8 +304,7 @@ public class JacksonAutoConfiguration {
}
private void configureModules(Jackson2ObjectMapperBuilder builder) {
Collection<Module> moduleBeans = getBeans(this.applicationContext, Module.class);
builder.modulesToInstall(moduleBeans.toArray(new Module[0]));
builder.modulesToInstall(this.modules.toArray(new Module[0]));
}
private void configureLocale(Jackson2ObjectMapperBuilder builder) {
@ -340,10 +338,6 @@ public class JacksonAutoConfiguration {
}
}
private static <T> Collection<T> getBeans(ListableBeanFactory beanFactory, Class<T> type) {
return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type).values();
}
}
}

View File

@ -50,6 +50,7 @@ import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
@ -447,6 +448,14 @@ class JacksonAutoConfigurationTests {
});
}
@Test
void jsonComponentThatInjectsObjectMapperCausesBeanCurrentlyInCreationException() {
this.contextRunner.withUserConfiguration(CircularDependencySerializerConfiguration.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure().hasRootCauseInstanceOf(BeanCurrentlyInCreationException.class);
});
}
private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class<?>... configClasses) {
this.contextRunner.withUserConfiguration(configClasses).run((context) -> {
DeserializationConfig deserializationConfig = context.getBean(ObjectMapper.class)
@ -657,4 +666,24 @@ class JacksonAutoConfigurationTests {
}
@JsonComponent
static class CircularDependencySerializer extends JsonSerializer<String> {
CircularDependencySerializer(ObjectMapper objectMapper) {
}
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
}
}
@Import(CircularDependencySerializer.class)
@Configuration(proxyBeanMethods = false)
static class CircularDependencySerializerConfiguration {
}
}