Ensure that Jersey and Jackson honour JAXB annotations
By default Jersey configures Jackson to use both Jackson annotations
and JAXB annotations when introspective types for (de)serialization.
However, the changes made in 5776d6a8
mean that Jersey no longer uses
its default ObjectMapper configuration and uses the auto-configured
ObjectMapper instead. This had the unwanted side-effect of leaving
Jersey with an ObjectMapper that only uses Jackson annotations and
ignores JAXB annotations.
This commit updates JerseyAutoConfiguration so that it will add the
JaxbAnnotationIntrospector to the auto-configured ObjectMapper for
both serialization and deserialization. It uses
AnnotationIntrospectorPair to ensure retain any existing
introspectors.
Closes gh-6310
This commit is contained in:
parent
ce3f4bd068
commit
8cbe30ab5e
|
@ -28,9 +28,11 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRegistration;
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.ext.ContextResolver;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.cfg.MapperConfig;
|
||||
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.glassfish.jersey.CommonProperties;
|
||||
|
@ -40,7 +42,6 @@ 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;
|
||||
|
@ -234,23 +235,57 @@ public class JerseyAutoConfiguration implements ServletContextAware {
|
|||
@Configuration
|
||||
static class JacksonResourceConfigCustomizer {
|
||||
|
||||
private static final String JAXB_ANNOTATION_INTROSPECTOR_CLASS_NAME = "com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector";
|
||||
|
||||
@Bean
|
||||
public ResourceConfigCustomizer resourceConfigCustomizer() {
|
||||
public ResourceConfigCustomizer resourceConfigCustomizer(
|
||||
final ObjectMapper objectMapper) {
|
||||
addJaxbAnnotationIntrospectorIfPresent(objectMapper);
|
||||
return new ResourceConfigCustomizer() {
|
||||
@Override
|
||||
public void customize(ResourceConfig config) {
|
||||
config.register(JacksonFeature.class);
|
||||
config.register(ObjectMapperContextResolver.class);
|
||||
config.register(new ObjectMapperContextResolver(objectMapper),
|
||||
ContextResolver.class);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Provider
|
||||
static class ObjectMapperContextResolver
|
||||
private void addJaxbAnnotationIntrospectorIfPresent(ObjectMapper objectMapper) {
|
||||
if (ClassUtils.isPresent(JAXB_ANNOTATION_INTROSPECTOR_CLASS_NAME,
|
||||
getClass().getClassLoader())) {
|
||||
new ObjectMapperCustomizer().addJaxbAnnotationIntrospector(objectMapper);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ObjectMapperCustomizer {
|
||||
|
||||
private void addJaxbAnnotationIntrospector(ObjectMapper objectMapper) {
|
||||
JaxbAnnotationIntrospector jaxbAnnotationIntrospector = new JaxbAnnotationIntrospector(
|
||||
objectMapper.getTypeFactory());
|
||||
objectMapper.setAnnotationIntrospectors(
|
||||
createPair(objectMapper.getSerializationConfig(),
|
||||
jaxbAnnotationIntrospector),
|
||||
createPair(objectMapper.getDeserializationConfig(),
|
||||
jaxbAnnotationIntrospector));
|
||||
}
|
||||
|
||||
private AnnotationIntrospector createPair(MapperConfig<?> config,
|
||||
JaxbAnnotationIntrospector jaxbAnnotationIntrospector) {
|
||||
return AnnotationIntrospector.pair(config.getAnnotationIntrospector(),
|
||||
jaxbAnnotationIntrospector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class ObjectMapperContextResolver
|
||||
implements ContextResolver<ObjectMapper> {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private ObjectMapperContextResolver(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectMapper getContext(Class<?> type) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.lang.annotation.Target;
|
|||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.junit.Test;
|
||||
|
@ -52,9 +53,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Tests for {@link JerseyAutoConfiguration} with a ObjectMapper.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.jackson.serialization-inclusion:non-null")
|
||||
@DirtiesContext
|
||||
public class JerseyAutoConfigurationObjectMapperProviderTests {
|
||||
|
||||
|
@ -62,12 +64,12 @@ public class JerseyAutoConfigurationObjectMapperProviderTests {
|
|||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
public void responseIsSerializedUsingAutoConfiguredObjectMapper() {
|
||||
ResponseEntity<String> response = this.restTemplate.getForEntity("/rest/message",
|
||||
String.class);
|
||||
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode());
|
||||
assertThat("{\"subject\":\"Jersey\",\"body\":null}")
|
||||
.isEqualTo(response.getBody());
|
||||
assertThat(response.getBody())
|
||||
.isEqualTo(String.format("{\"subject\":\"Jersey\"}"));
|
||||
}
|
||||
|
||||
@MinimalWebConfiguration
|
||||
|
@ -121,6 +123,11 @@ public class JerseyAutoConfigurationObjectMapperProviderTests {
|
|||
this.body = body;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public String getFoo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
|
|
Loading…
Reference in New Issue