From e2a35e7ce931d3445b20ed2d09c41a3912d2e9c5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 10 Dec 2014 19:42:20 +0100 Subject: [PATCH] DATAREST-424 - Registered HttpMessageConverters now implement Ordered. To be able to control the order of the HttpMessageConverter beans registered by RepositoryRestMvcConfiguration we now use a dedicated subtype of TypeConstrainedMappingJackson2HttpMessageConverter which additionally implements Ordered. --- .../RepositoryRestMvcConfiguration.java | 45 +++++++++++--- ...ryRestMvConfigurationIntegrationTests.java | 62 +++++++++++++++++++ 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index 598540e59..b086ebb9b 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -38,6 +38,7 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.context.support.MessageSourceAccessor; import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.io.ClassPathResource; @@ -398,17 +399,20 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon public MappingJackson2HttpMessageConverter jacksonHttpMessageConverter() { List mediaTypes = new ArrayList(); - mediaTypes.addAll(Arrays.asList(RestMediaTypes.SCHEMA_JSON, // - RestMediaTypes.JSON_PATCH_JSON, RestMediaTypes.MERGE_PATCH_JSON, // - RestMediaTypes.SPRING_DATA_VERBOSE_JSON, RestMediaTypes.SPRING_DATA_COMPACT_JSON)); // Configure this mapper to be used if HAL is not the default media type if (!config().useHalAsDefaultJsonMediaType()) { mediaTypes.add(MediaType.APPLICATION_JSON); } - MappingJackson2HttpMessageConverter jacksonConverter = new TypeConstrainedMappingJackson2HttpMessageConverter( - ResourceSupport.class); + int order = config().useHalAsDefaultJsonMediaType() ? Ordered.LOWEST_PRECEDENCE - 1 + : Ordered.LOWEST_PRECEDENCE - 10; + + mediaTypes.addAll(Arrays.asList(RestMediaTypes.SCHEMA_JSON, // + RestMediaTypes.JSON_PATCH_JSON, RestMediaTypes.MERGE_PATCH_JSON, // + RestMediaTypes.SPRING_DATA_VERBOSE_JSON, RestMediaTypes.SPRING_DATA_COMPACT_JSON)); + + MappingJackson2HttpMessageConverter jacksonConverter = new ResourceSupportHttpMessageConverter(order); jacksonConverter.setObjectMapper(objectMapper()); jacksonConverter.setSupportedMediaTypes(mediaTypes); @@ -430,8 +434,10 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon mediaTypes.add(MediaType.APPLICATION_JSON); } - MappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter( - ResourceSupport.class); + int order = config().useHalAsDefaultJsonMediaType() ? Ordered.LOWEST_PRECEDENCE - 10 + : Ordered.LOWEST_PRECEDENCE - 1; + + MappingJackson2HttpMessageConverter converter = new ResourceSupportHttpMessageConverter(order); converter.setObjectMapper(halObjectMapper()); converter.setSupportedMediaTypes(mediaTypes); @@ -704,6 +710,31 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon return new AlpsResourceProcessor(config()); } + private static class ResourceSupportHttpMessageConverter extends TypeConstrainedMappingJackson2HttpMessageConverter + implements Ordered { + + private final int order; + + /** + * Creates a new {@link ResourceSupportHttpMessageConverter} with the given order. + * + * @param order the order for the {@link HttpMessageConverter}. + */ + public ResourceSupportHttpMessageConverter(int order) { + super(ResourceSupport.class); + this.order = order; + } + + /* + * (non-Javadoc) + * @see org.springframework.core.Ordered#getOrder() + */ + @Override + public int getOrder() { + return order; + } + } + /** * Override this method to add additional configuration. * diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java index 3a23a190d..cf986ac51 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java @@ -20,12 +20,14 @@ import static org.junit.Assert.*; import java.util.Collection; import java.util.Date; +import java.util.List; import java.util.Locale; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,12 +36,14 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.webmvc.RepositoryLinksResource; +import org.springframework.data.rest.webmvc.RestMediaTypes; import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module; import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.format.datetime.DateFormatter; import org.springframework.hateoas.LinkDiscoverers; +import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.core.DefaultRelProvider; import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; @@ -154,6 +158,35 @@ public class RepositoryRestMvConfigurationIntegrationTests { } } + /** + * @see DATAREST-424 + */ + @Test + public void halHttpMethodConverterIsRegisteredBeforeTheGeneralOne() { + + CollectingComponent component = context.getBean(CollectingComponent.class); + List> converters = component.converters; + + assertThat(converters.get(0).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON)); + assertThat(converters.get(1).getSupportedMediaTypes(), hasItem(RestMediaTypes.SCHEMA_JSON)); + } + + /** + * @see DATAREST-424 + */ + @Test + public void halHttpMethodConverterIsRegisteredAfterTheGeneralOneIfHalIsDisabledAsDefaultMediaType() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(NonHalConfiguration.class); + CollectingComponent component = context.getBean(CollectingComponent.class); + context.close(); + + List> converters = component.converters; + + assertThat(converters.get(0).getSupportedMediaTypes(), hasItem(RestMediaTypes.SCHEMA_JSON)); + assertThat(converters.get(1).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON)); + } + @Configuration static class ExtendingConfiguration extends RepositoryRestMvcConfiguration { @@ -162,6 +195,11 @@ public class RepositoryRestMvConfigurationIntegrationTests { return new DefaultRelProvider(); } + @Bean + public CollectingComponent collectingComponent() { + return new CollectingComponent(); + } + @Override protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { @@ -173,8 +211,32 @@ public class RepositoryRestMvConfigurationIntegrationTests { } } + @Configuration + static class NonHalConfiguration extends RepositoryRestMvcConfiguration { + + @Bean + public CollectingComponent collectingComponent() { + return new CollectingComponent(); + } + + @Override + protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { + config.useHalAsDefaultJsonMediaType(false); + } + } + static class Sample { public Date date; } + + static class CollectingComponent { + + List> converters; + + @Autowired + public void setConverters(List> converters) { + this.converters = converters; + } + } }