diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java index 3804ebc16f24..64f68b78a61e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java @@ -254,7 +254,7 @@ public static UriComponentsBuilder fromMethodCall(Object invocationInfo) { public static UriComponentsBuilder fromMethodCall(UriComponentsBuilder builder, Object invocationInfo) { Assert.isInstanceOf(MethodInvocationInfo.class, invocationInfo); MethodInvocationInfo info = (MethodInvocationInfo) invocationInfo; - return fromMethod(builder, info.getControllerMethod(), info.getArgumentValues()); + return fromMethod(builder, info.getControllerType(), info.getControllerMethod(), info.getArgumentValues()); } /** @@ -362,8 +362,12 @@ public static UriComponentsBuilder fromMethod(Method method, Object... args) { * @return a UriComponentsBuilder instance, never {@code null} */ public static UriComponentsBuilder fromMethod(UriComponentsBuilder baseUrl, Method method, Object... args) { + return fromMethod(baseUrl, method.getDeclaringClass(), method, args); + } + + private static UriComponentsBuilder fromMethod(UriComponentsBuilder baseUrl, Class controllerType, Method method, Object... args) { baseUrl = getBaseUrlToUse(baseUrl); - String typePath = getTypeRequestMapping(method.getDeclaringClass()); + String typePath = getTypeRequestMapping(controllerType); String methodPath = getMethodRequestMapping(method); String path = pathMatcher.combine(typePath, methodPath); baseUrl.path(path); @@ -560,7 +564,7 @@ public static T on(Class controllerType) { */ public static T controller(Class controllerType) { Assert.notNull(controllerType, "'controllerType' must not be null"); - return initProxy(controllerType, new ControllerMethodInvocationInterceptor()); + return initProxy(controllerType, new ControllerMethodInvocationInterceptor(controllerType)); } @SuppressWarnings("unchecked") @@ -634,11 +638,19 @@ private static class ControllerMethodInvocationInterceptor private static final Method getArgumentValues = ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues"); + private static final Method getControllerType = + ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerType"); + private Method controllerMethod; private Object[] argumentValues; + private Class controllerType; + ControllerMethodInvocationInterceptor(Class controllerType) { + this.controllerType = controllerType; + } + @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { if (getControllerMethod.equals(method)) { @@ -647,6 +659,9 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr else if (getArgumentValues.equals(method)) { return this.argumentValues; } + else if (getControllerType.equals(method)) { + return this.controllerType; + } else if (ReflectionUtils.isObjectMethod(method)) { return ReflectionUtils.invokeMethod(method, obj, args); } @@ -670,6 +685,8 @@ public interface MethodInvocationInfo { Method getControllerMethod(); Object[] getArgumentValues(); + + Class getControllerType(); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java index 8e1b66392582..7aa613743fae 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java @@ -229,6 +229,14 @@ public void testFromMethodCall() { assertThat(uriComponents.toUriString(), endsWith("/something/else")); } + @Test + public void testFromMethodCallOnSubclass() { + UriComponents uriComponents = fromMethodCall(on(ExtendedController.class).myMethod(null)).build(); + + assertThat(uriComponents.toUriString(), startsWith("http://localhost")); + assertThat(uriComponents.toUriString(), endsWith("/extended/else")); + } + @Test public void testFromMethodCallWithTypeLevelUriVars() { UriComponents uriComponents = fromMethodCall(on( @@ -418,6 +426,11 @@ HttpEntity methodWithMultiValueRequestParams(@PathVariable String id, } } + @RequestMapping("/extended") + static class ExtendedController extends ControllerWithMethods { + + } + @RequestMapping("/user/{userId}/contacts") static class UserContactController {