From 20befe9a583ff990963ddac58f468d738f5b990b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 19 Mar 2014 14:16:34 +0100 Subject: [PATCH] #134 - Fixed initialization of HttpMessageConverters for HAL. The Jackson(2)ModuleRegisteringBeanPostProcessor now uses postProcess*Before*Initialization to make sure, afterPropertiesSet() has not been called on the target components which might have propagated the original HttpMessageConverters into other internal components. With this fix, adding the HttpMessageConverter for HAL is added before the call and thus will be propagated to downstream components. --- ...ermediaSupportBeanDefinitionRegistrar.java | 42 +++++++++---------- ...nableHypermediaSupportIntegrationTest.java | 40 ++++++++++++++++++ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java b/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java index ca93c808..8c99cc81 100644 --- a/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java +++ b/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java @@ -220,7 +220,7 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe * * @author Oliver Gierke */ - private static class Jackson2ModuleRegisteringBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { + static class Jackson2ModuleRegisteringBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { private CurieProvider curieProvider; private RelProvider relProvider; @@ -244,15 +244,6 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) - */ - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RequestMappingHandlerAdapter) { @@ -263,8 +254,8 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe if (bean instanceof AnnotationMethodHandlerAdapter) { AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean; - List> augmentedConverters = potentiallyRegisterModule(Arrays - .asList(adapter.getMessageConverters())); + List> augmentedConverters = potentiallyRegisterModule(Arrays.asList(adapter + .getMessageConverters())); adapter .setMessageConverters(augmentedConverters.toArray(new HttpMessageConverter[augmentedConverters.size()])); } @@ -272,6 +263,15 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe return bean; } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + private List> potentiallyRegisterModule(List> converters) { for (HttpMessageConverter converter : converters) { @@ -333,15 +333,6 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) - */ - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RequestMappingHandlerAdapter) { @@ -361,6 +352,15 @@ class HypermediaSupportBeanDefinitionRegistrar implements ImportBeanDefinitionRe return bean; } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + private List> registerModule(List> converters) { org.codehaus.jackson.map.ObjectMapper objectMapper = new org.codehaus.jackson.map.ObjectMapper(); diff --git a/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java b/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java index 34090eca..e6916f8b 100644 --- a/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java +++ b/src/test/java/org/springframework/hateoas/config/EnableHypermediaSupportIntegrationTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.Arrays; +import java.util.List; import java.util.Map; import org.hamcrest.Matchers; @@ -36,13 +37,17 @@ import org.springframework.hateoas.LinkDiscoverers; import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.RelProvider; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; +import org.springframework.hateoas.config.HypermediaSupportBeanDefinitionRegistrar.Jackson2ModuleRegisteringBeanPostProcessor; import org.springframework.hateoas.core.DelegatingEntityLinks; import org.springframework.hateoas.core.DelegatingRelProvider; import org.springframework.hateoas.hal.HalLinkDiscoverer; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import com.fasterxml.jackson.databind.ObjectMapper; @@ -106,6 +111,41 @@ public class EnableHypermediaSupportIntegrationTest { instanceOf(MappingJackson2HttpMessageConverter.class), instanceOf(MappingJacksonHttpMessageConverter.class))); } + /** + * @see #134 + */ + @Test + @SuppressWarnings("unchecked") + public void halSetupIsAppliedToAllTransitiveComponentsInRequestMappingHandlerAdapter() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HalConfig.class); + + Jackson2ModuleRegisteringBeanPostProcessor postProcessor = new HypermediaSupportBeanDefinitionRegistrar.Jackson2ModuleRegisteringBeanPostProcessor(); + postProcessor.setBeanFactory(context); + + RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class); + + assertThat(adapter.getMessageConverters().get(0).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON)); + + boolean found = false; + + for (HandlerMethodArgumentResolver resolver : adapter.getArgumentResolvers().getResolvers()) { + + if (resolver instanceof AbstractMessageConverterMethodArgumentResolver) { + + found = true; + + AbstractMessageConverterMethodArgumentResolver processor = (AbstractMessageConverterMethodArgumentResolver) resolver; + List> converters = (List>) ReflectionTestUtils.getField( + processor, "messageConverters"); + + assertThat(converters.get(0).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON)); + } + } + + assertThat(found, is(true)); + } + @Configuration @Import(DelegateConfig.class) static class HalConfig {