DATAREST-597 - Improved AlpsJsonHttpMessageConverter for Spring 4.2 compatibility.

AlpsJsonHttpMessageConverter now implements ResponseBodyAdvice to apply the potentially necessary conversion from RootResourceInformation to Alps to make sure we also get it applied on latest Spring 4.2 snapshots that invoke a newly introduced method to handle generic types in Jackson marshaling.
This commit is contained in:
Oliver Gierke
2015-06-25 16:04:31 +02:00
parent f8c7a1c376
commit bd0483f5e6
3 changed files with 35 additions and 14 deletions

View File

@@ -15,19 +15,20 @@
*/
package org.springframework.data.rest.webmvc.alps;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.rest.webmvc.RootResourceInformation;
import org.springframework.hateoas.alps.Alps;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -38,7 +39,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*
* @author Oliver Gierke
*/
public class AlpsJsonHttpMessageConverter extends MappingJackson2HttpMessageConverter {
public class AlpsJsonHttpMessageConverter extends MappingJackson2HttpMessageConverter
implements ResponseBodyAdvice<Object> {
private static final MediaType ALPS_MEDIA_TYPE = MediaType.parseMediaType("application/alps+json");
@@ -83,15 +85,22 @@ public class AlpsJsonHttpMessageConverter extends MappingJackson2HttpMessageConv
/*
* (non-Javadoc)
* @see org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#writeInternal(java.lang.Object, org.springframework.http.HttpOutputMessage)
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#beforeBodyWrite(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.http.MediaType, java.lang.Class, org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse)
*/
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
Object toWrite = object instanceof RootResourceInformation ? converter.convert((RootResourceInformation) object)
: object;
return body instanceof RootResourceInformation ? converter.convert((RootResourceInformation) body) : body;
}
super.writeInternal(toWrite, outputMessage);
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#supports(org.springframework.core.MethodParameter, java.lang.Class)
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return converterType.equals(AlpsJsonHttpMessageConverter.class);
}
}

View File

@@ -122,6 +122,7 @@ import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;
@@ -496,6 +497,10 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
handlerAdapter.setWebBindingInitializer(initializer);
handlerAdapter.setMessageConverters(messageConverters);
if (config().metadataConfiguration().alpsEnabled()) {
handlerAdapter.setResponseBodyAdvice(Arrays.<ResponseBodyAdvice<?>> asList(alpsJsonHttpMessageConverter()));
}
return handlerAdapter;
}
@@ -589,7 +594,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
if (config().metadataConfiguration().alpsEnabled()) {
messageConverters.add(new AlpsJsonHttpMessageConverter(alpsConverter()));
messageConverters.add(alpsJsonHttpMessageConverter());
}
if (config().getDefaultMediaType().equals(MediaTypes.HAL_JSON)) {
@@ -609,6 +614,11 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
return messageConverters;
}
@Bean
public AlpsJsonHttpMessageConverter alpsJsonHttpMessageConverter() {
return new AlpsJsonHttpMessageConverter(alpsConverter());
}
/*
* (non-Javadoc)
* @see org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration#pageableResolver()

View File

@@ -40,6 +40,7 @@ import org.springframework.data.geo.Point;
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.alps.AlpsJsonHttpMessageConverter;
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module;
import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
@@ -153,11 +154,12 @@ public class RepositoryRestMvConfigurationIntegrationTests {
@Test
public void registeredHttpMessageConvertersAreTypeConstrained() {
Collection<MappingJackson2HttpMessageConverter> converters = context.getBeansOfType(
MappingJackson2HttpMessageConverter.class).values();
Collection<MappingJackson2HttpMessageConverter> converters = context
.getBeansOfType(MappingJackson2HttpMessageConverter.class).values();
for (HttpMessageConverter<?> converter : converters) {
assertThat(converter, is(instanceOf(TypeConstrainedMappingJackson2HttpMessageConverter.class)));
assertThat(converter, is(anyOf(instanceOf(TypeConstrainedMappingJackson2HttpMessageConverter.class),
instanceOf(AlpsJsonHttpMessageConverter.class))));
}
}