#219 - HAL setup now registers a more strict HttpMessageConverter.

Previously we registered a special HttpMessageConverter with a custom ObjectMapper to deploy the HAL customizations. That converter was added to Spring MVC registered HandlerAdapters and registered as the first converter.

In case Spring MVC handled a request with Accept header */* or no Accept header at all, this meant that this converter kicked in and served HAL even for objects that don't need the customizations.

We now restrict the applicability of that special HttpMessageConverter to subtypes of ResourceSupport so that it will only be chosen if the object to render is of such type.
This commit is contained in:
Oliver Gierke
2014-07-25 10:24:30 +02:00
parent f4c43b26c4
commit 5882fcf0d6
4 changed files with 175 additions and 38 deletions

View File

@@ -44,6 +44,7 @@ import org.springframework.hateoas.EntityLinks;
import org.springframework.hateoas.LinkDiscoverer;
import org.springframework.hateoas.LinkDiscoverers;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.core.AnnotationRelProvider;
import org.springframework.hateoas.core.DefaultRelProvider;
@@ -52,6 +53,7 @@ import org.springframework.hateoas.core.EvoInflectorRelProvider;
import org.springframework.hateoas.hal.CurieProvider;
import org.springframework.hateoas.hal.HalLinkDiscoverer;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.plugin.core.PluginRegistry;
@@ -278,7 +280,8 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe
halObjectMapper.registerModule(new Jackson2HalModule());
halObjectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider));
MappingJackson2HttpMessageConverter halConverter = new MappingJackson2HttpMessageConverter();
MappingJackson2HttpMessageConverter halConverter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
halConverter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
halConverter.setObjectMapper(halObjectMapper);

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.mvc;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Extension of {@link MappingJackson2HttpMessageConverter} to constrain the ability to read and write HTTP message
* based on the target type. Useful in case the {@link ObjectMapper} about to be configured has customizations that
* sholny be applied to object trees of a certain base type.
*
* @author Oliver Gierke
*/
public class TypeConstrainedMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
private final Class<?> type;
/**
* Creates a new {@link TypeConstrainedMappingJackson2HttpMessageConverter} for the given type.
*
* @param type must not be {@literal null}.
*/
public TypeConstrainedMappingJackson2HttpMessageConverter(Class<?> type) {
Assert.notNull(type, "Type must not be null!");
this.type = type;
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#canRead(java.lang.Class, org.springframework.http.MediaType)
*/
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return type.isAssignableFrom(clazz) && super.canRead(clazz, mediaType);
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#canWrite(java.lang.Class, org.springframework.http.MediaType)
*/
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return type.isAssignableFrom(clazz) && super.canWrite(clazz, mediaType);
}
}