diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java index a7fd37196a..de3d308c21 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java @@ -25,6 +25,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.ws.rs.ext.ContextResolver; +import javax.xml.bind.annotation.XmlElement; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.ObjectMapper; @@ -39,6 +40,7 @@ import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletProperties; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureOrder; @@ -201,17 +203,14 @@ public class JerseyAutoConfiguration implements ServletContextAware { } + @Configuration @ConditionalOnClass(JacksonFeature.class) @ConditionalOnSingleCandidate(ObjectMapper.class) - @Configuration static class JacksonResourceConfigCustomizer { - private static final String JAXB_ANNOTATION_INTROSPECTOR_CLASS_NAME = "com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector"; - @Bean public ResourceConfigCustomizer resourceConfigCustomizer( final ObjectMapper objectMapper) { - addJaxbAnnotationIntrospectorIfPresent(objectMapper); return (ResourceConfig config) -> { config.register(JacksonFeature.class); config.register(new ObjectMapperContextResolver(objectMapper), @@ -219,16 +218,12 @@ public class JerseyAutoConfiguration implements ServletContextAware { }; } - private void addJaxbAnnotationIntrospectorIfPresent(ObjectMapper objectMapper) { - if (ClassUtils.isPresent(JAXB_ANNOTATION_INTROSPECTOR_CLASS_NAME, - getClass().getClassLoader())) { - new ObjectMapperCustomizer().addJaxbAnnotationIntrospector(objectMapper); - } - } - - private static final class ObjectMapperCustomizer { + @Configuration + @ConditionalOnClass({ JaxbAnnotationIntrospector.class, XmlElement.class }) + static class JaxbObjectMapperCustomizer { - private void addJaxbAnnotationIntrospector(ObjectMapper objectMapper) { + @Autowired + public void addJaxbAnnotationIntrospector(ObjectMapper objectMapper) { JaxbAnnotationIntrospector jaxbAnnotationIntrospector = new JaxbAnnotationIntrospector( objectMapper.getTypeFactory()); objectMapper.setAnnotationIntrospectors( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationTests.java index 73fc1130ca..75a4b64fda 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationTests.java @@ -16,12 +16,16 @@ package org.springframework.boot.autoconfigure.jersey; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; import org.glassfish.jersey.server.ResourceConfig; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener; import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -72,6 +76,48 @@ public class JerseyAutoConfigurationTests { }); } + @Test + public void whenJaxbIsAvailableTheObjectMapperIsCustomizedWithAnAnnotationIntrospector() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)) + .run((context) -> { + ObjectMapper objectMapper = context.getBean(ObjectMapper.class); + assertThat(objectMapper.getSerializationConfig() + .getAnnotationIntrospector().allIntrospectors().stream() + .filter(JaxbAnnotationIntrospector.class::isInstance)) + .hasSize(1); + }); + } + + @Test + public void whenJaxbIsNotAvailableTheObjectMapperCustomizationBacksOff() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader("javax.xml.bind.annotation")) + .run((context) -> { + ObjectMapper objectMapper = context.getBean(ObjectMapper.class); + assertThat(objectMapper.getSerializationConfig() + .getAnnotationIntrospector().allIntrospectors().stream() + .filter(JaxbAnnotationIntrospector.class::isInstance)) + .isEmpty(); + }); + } + + @Test + public void whenJacksonJaxbModuleIsNotAvailableTheObjectMapperCustomizationBacksOff() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)) + .withClassLoader( + new FilteredClassLoader(JaxbAnnotationIntrospector.class)) + .run((context) -> { + ObjectMapper objectMapper = context.getBean(ObjectMapper.class); + assertThat(objectMapper.getSerializationConfig() + .getAnnotationIntrospector().allIntrospectors().stream() + .filter(JaxbAnnotationIntrospector.class::isInstance)) + .isEmpty(); + }); + } + @Configuration static class ResourceConfigConfiguration {