Browse Source

SPR-13033: Use @RequestMapping of correct class

MvcUriComponentsBuilder::fromMethodCall creates wrong URLs with derived
controller classes. The @RequestMapping of the declaring class of the
method that is called is used instead of the @RequstMapping of the
given controller class.

https://jira.spring.io/browse/SPR-13033
pull/800/merge
james 11 years ago committed by Rossen Stoyanchev
parent
commit
e41877d64e
  1. 23
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
  2. 13
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java

23
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java

@ -254,7 +254,7 @@ public class MvcUriComponentsBuilder {
public static UriComponentsBuilder fromMethodCall(UriComponentsBuilder builder, Object invocationInfo) { public static UriComponentsBuilder fromMethodCall(UriComponentsBuilder builder, Object invocationInfo) {
Assert.isInstanceOf(MethodInvocationInfo.class, invocationInfo); Assert.isInstanceOf(MethodInvocationInfo.class, invocationInfo);
MethodInvocationInfo info = (MethodInvocationInfo) 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 class MvcUriComponentsBuilder {
* @return a UriComponentsBuilder instance, never {@code null} * @return a UriComponentsBuilder instance, never {@code null}
*/ */
public static UriComponentsBuilder fromMethod(UriComponentsBuilder baseUrl, Method method, Object... args) { 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); baseUrl = getBaseUrlToUse(baseUrl);
String typePath = getTypeRequestMapping(method.getDeclaringClass()); String typePath = getTypeRequestMapping(controllerType);
String methodPath = getMethodRequestMapping(method); String methodPath = getMethodRequestMapping(method);
String path = pathMatcher.combine(typePath, methodPath); String path = pathMatcher.combine(typePath, methodPath);
baseUrl.path(path); baseUrl.path(path);
@ -560,7 +564,7 @@ public class MvcUriComponentsBuilder {
*/ */
public static <T> T controller(Class<T> controllerType) { public static <T> T controller(Class<T> controllerType) {
Assert.notNull(controllerType, "'controllerType' must not be null"); Assert.notNull(controllerType, "'controllerType' must not be null");
return initProxy(controllerType, new ControllerMethodInvocationInterceptor()); return initProxy(controllerType, new ControllerMethodInvocationInterceptor(controllerType));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -634,11 +638,19 @@ public class MvcUriComponentsBuilder {
private static final Method getArgumentValues = private static final Method getArgumentValues =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues"); ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues");
private static final Method getControllerType =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerType");
private Method controllerMethod; private Method controllerMethod;
private Object[] argumentValues; private Object[] argumentValues;
private Class<?> controllerType;
ControllerMethodInvocationInterceptor(Class<?> controllerType) {
this.controllerType = controllerType;
}
@Override @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
if (getControllerMethod.equals(method)) { if (getControllerMethod.equals(method)) {
@ -647,6 +659,9 @@ public class MvcUriComponentsBuilder {
else if (getArgumentValues.equals(method)) { else if (getArgumentValues.equals(method)) {
return this.argumentValues; return this.argumentValues;
} }
else if (getControllerType.equals(method)) {
return this.controllerType;
}
else if (ReflectionUtils.isObjectMethod(method)) { else if (ReflectionUtils.isObjectMethod(method)) {
return ReflectionUtils.invokeMethod(method, obj, args); return ReflectionUtils.invokeMethod(method, obj, args);
} }
@ -670,6 +685,8 @@ public class MvcUriComponentsBuilder {
Method getControllerMethod(); Method getControllerMethod();
Object[] getArgumentValues(); Object[] getArgumentValues();
Class<?> getControllerType();
} }

13
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java

@ -229,6 +229,14 @@ public class MvcUriComponentsBuilderTests {
assertThat(uriComponents.toUriString(), endsWith("/something/else")); 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 @Test
public void testFromMethodCallWithTypeLevelUriVars() { public void testFromMethodCallWithTypeLevelUriVars() {
UriComponents uriComponents = fromMethodCall(on( UriComponents uriComponents = fromMethodCall(on(
@ -418,6 +426,11 @@ public class MvcUriComponentsBuilderTests {
} }
} }
@RequestMapping("/extended")
static class ExtendedController extends ControllerWithMethods {
}
@RequestMapping("/user/{userId}/contacts") @RequestMapping("/user/{userId}/contacts")
static class UserContactController { static class UserContactController {

Loading…
Cancel
Save