DATAREST-326 - Improved configuration setup for better Boot compatibility.

We now don't expose the PersistentEntityJackson2Module as bean anymore to prevent global registration in case of a Boot setup. The HttpMessageConverters registered are now TypeConstrainedMappingJackson2HttpMessageConverters so that they only get used of the object to marshal is of type ResourceSupport.
This commit is contained in:
Oliver Gierke
2014-07-25 15:25:11 +02:00
parent aa28aebca5
commit 2d64fb4d84
5 changed files with 50 additions and 11 deletions

View File

@@ -16,7 +16,7 @@
</parent>
<properties>
<spring.hateoas>0.15.0.RELEASE</spring.hateoas>
<spring.hateoas>0.16.0.BUILD-SNAPSHOT</spring.hateoas>
<springplugin>1.1.0.RELEASE</springplugin>
<evoinflector>1.2</evoinflector>
</properties>

View File

@@ -115,7 +115,7 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha
for (HttpMessageConverter converter : messageConverters) {
if (!converter.canRead(domainType, contentType)) {
if (!converter.canRead(PersistentEntityResource.class, contentType)) {
continue;
}

View File

@@ -98,12 +98,14 @@ import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.ResourceProcessor;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.core.EvoInflectorRelProvider;
import org.springframework.hateoas.hal.CurieProvider;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.hateoas.hal.Jackson2HalModule.HalHandlerInstantiator;
import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@@ -373,7 +375,11 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
*/
@Bean
public ObjectMapper objectMapper() {
return basicObjectMapper();
ObjectMapper mapper = basicObjectMapper();
mapper.registerModule(persistentEntityJackson2Module());
return mapper;
}
/**
@@ -394,7 +400,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
mediaTypes.add(MediaType.APPLICATION_JSON);
}
MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
MappingJackson2HttpMessageConverter jacksonConverter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
jacksonConverter.setObjectMapper(objectMapper());
jacksonConverter.setSupportedMediaTypes(mediaTypes);
@@ -416,7 +423,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
mediaTypes.add(MediaType.APPLICATION_JSON);
}
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
MappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
converter.setObjectMapper(halObjectMapper());
converter.setSupportedMediaTypes(mediaTypes);
@@ -429,6 +437,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
HalHandlerInstantiator instantiator = new HalHandlerInstantiator(getDefaultedRelProvider(), curieProvider);
ObjectMapper mapper = basicObjectMapper();
mapper.registerModule(persistentEntityJackson2Module());
mapper.registerModule(new Jackson2HalModule());
mapper.setHandlerInstantiator(instantiator);
@@ -508,8 +517,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
*
* @return
*/
@Bean
public Module persistentEntityJackson2Module() {
private Module persistentEntityJackson2Module() {
return new PersistentEntityJackson2Module(resourceMappings(), persistentEntities(), config(),
uriToEntityConverter());
}
@@ -555,6 +563,10 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
messageConverters.add(halJacksonHttpMessageConverter());
}
MappingJackson2HttpMessageConverter fallbackJsonConverter = new MappingJackson2HttpMessageConverter();
fallbackJsonConverter.setObjectMapper(basicObjectMapper());
messageConverters.add(fallbackJsonConverter);
messageConverters.add(uriListHttpMessageConverter());
return messageConverters;
@@ -622,12 +634,12 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
private ObjectMapper basicObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// Our special PersistentEntityResource Module
objectMapper.registerModule(persistentEntityJackson2Module());
objectMapper.registerModule(geoModule);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(geoModule);
Jackson2DatatypeHelper.configureObjectMapper(objectMapper);
// Configure custom Modules
configureJacksonObjectMapper(objectMapper);

View File

@@ -380,7 +380,7 @@ public abstract class AbstractWebIntegrationTests {
public void servesHalWhenJsonIsRequested() throws Exception {
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON)). //
andExpect(content().contentType(MediaType.APPLICATION_JSON)). //
andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)). //
andExpect(jsonPath("$._links", notNullValue()));
}

View File

@@ -18,12 +18,14 @@ package org.springframework.data.rest.webmvc.config;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Collection;
import java.util.Date;
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.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -32,13 +34,16 @@ 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.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.core.DefaultRelProvider;
import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
@@ -127,6 +132,28 @@ public class RepositoryRestMvConfigurationIntegrationTests {
assertThat(result, is((Object) formatter.print(sample.date, Locale.US)));
}
/**
* @see DATAREST-362
*/
@Test(expected = NoSuchBeanDefinitionException.class)
public void doesNotExposePersistentEntityJackson2ModuleAsBean() {
context.getBean(PersistentEntityJackson2Module.class);
}
/**
* @see DATAREST-362
*/
@Test
public void registeredHttpMessageConvertersAreTypeConstrained() {
Collection<MappingJackson2HttpMessageConverter> converters = context.getBeansOfType(
MappingJackson2HttpMessageConverter.class).values();
for (HttpMessageConverter<?> converter : converters) {
assertThat(converter, is(instanceOf(TypeConstrainedMappingJackson2HttpMessageConverter.class)));
}
}
@Configuration
static class ExtendingConfiguration extends RepositoryRestMvcConfiguration {