From 037a27e2578371a99b225c043576b9b37685ac55 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 16 Dec 2015 11:13:24 +0000 Subject: [PATCH] Add a workaround for DATACMNS-776 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spring Data’s web support includes a handler method argument resolver, ProxyingHandlerMethodArgumentResolver, that inaccurately claims that it can handle all interface handler method arguments. This causes problems for handler methods that take Spring Mobile’s Device as an argument as the proxied Device instance does not behave correctly. This commit works around the problem by assigning an order to the WebMvcConfigurerAdapter that registers Spring Mobile’s argument resolver with Spring MVC. This ordering ensures that Spring Mobile’s resolver takes precedence over Spring Data’s for Device arguments. Closes gh-4163 --- .../DeviceResolverAutoConfiguration.java | 2 + .../DeviceResolverAutoConfigurationTests.java | 38 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfiguration.java index 5d41a1a433..8e7da6bcb4 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.mobile.device.DeviceHandlerMethodArgumentResolver; import org.springframework.mobile.device.DeviceResolver; import org.springframework.mobile.device.DeviceResolverHandlerInterceptor; @@ -48,6 +49,7 @@ public class DeviceResolverAutoConfiguration { @Configuration @ConditionalOnWebApplication + @Order(0) protected static class DeviceResolverMvcConfiguration extends WebMvcConfigurerAdapter { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfigurationTests.java index 4a02dfc93a..b4e2abaee5 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceResolverAutoConfigurationTests.java @@ -20,15 +20,23 @@ import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; +import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration; +import org.springframework.boot.autoconfigure.test.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.mobile.device.Device; import org.springframework.mobile.device.DeviceHandlerMethodArgumentResolver; import org.springframework.mobile.device.DeviceResolverHandlerInterceptor; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockServletContext; import org.springframework.stereotype.Controller; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.HandlerInterceptor; @@ -38,6 +46,8 @@ import static org.hamcrest.Matchers.hasItemInArray; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * Tests for {@link DeviceResolverAutoConfiguration}. @@ -76,10 +86,7 @@ public class DeviceResolverAutoConfigurationTests { public void deviceResolverHandlerInterceptorRegistered() throws Exception { this.context = new AnnotationConfigWebApplicationContext(); this.context.setServletContext(new MockServletContext()); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - DeviceResolverAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); + this.context.register(Config.class); this.context.refresh(); RequestMappingHandlerMapping mapping = this.context .getBean(RequestMappingHandlerMapping.class); @@ -89,7 +96,23 @@ public class DeviceResolverAutoConfigurationTests { hasItemInArray(instanceOf(DeviceResolverHandlerInterceptor.class))); } + @Test + public void deviceHandlerMethodArgumentWorksWithSpringData() throws Exception { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.register(Config.class); + this.context.setServletContext(new MockServletContext()); + this.context.refresh(); + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + mockMvc.perform(get("/")).andExpect(status().isOk()); + } + @Configuration + @ImportAutoConfiguration({ WebMvcAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + DeviceResolverAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SpringDataWebAutoConfiguration.class, + RepositoryRestMvcAutoConfiguration.class }) protected static class Config { @Bean @@ -103,8 +126,11 @@ public class DeviceResolverAutoConfigurationTests { protected static class MyController { @RequestMapping("/") - public void test() { - + public ResponseEntity test(Device device) { + if (device.getDevicePlatform() != null) { + return new ResponseEntity<>(HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } }