Replace MvcUrls with MvcUriComponentsBuilder

Issue: SPR-8826
This commit is contained in:
Rossen Stoyanchev
2013-10-25 22:25:06 -04:00
parent e7f89f87c1
commit cf5db8362b
13 changed files with 722 additions and 819 deletions

View File

@@ -19,8 +19,6 @@ package org.springframework.web.servlet.config;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -58,8 +56,6 @@ import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
@@ -67,6 +63,7 @@ import org.springframework.web.context.request.async.DeferredResultProcessingInt
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptorAdapter;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.CompositeUriComponentsContributor;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
@@ -80,14 +77,12 @@ import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.support.MvcUrls;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.util.UriComponents;
import static org.junit.Assert.*;
import static org.springframework.web.servlet.mvc.support.MvcUrlUtils.*;
/**
* @author Keith Donald
@@ -155,20 +150,11 @@ public class MvcNamespaceTests {
adapter.handle(request, response, handlerMethod);
assertTrue(handler.recordedValidationError);
// MvcUrls
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
try {
Date now = new Date();
TestController testController = controller(TestController.class);
testController.testBind(now, null, null);
MvcUrls mvcUrls = this.appContext.getBean(MvcUrls.class);
UriComponents uriComponents = mvcUrls.linkToMethodOn(testController);
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
assertEquals("http://localhost/?date=" + dateFormat.format(now), uriComponents.toUriString());
}
finally {
RequestContextHolder.resetRequestAttributes();
}
CompositeUriComponentsContributor uriComponentsContributor = this.appContext.getBean(
MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME,
CompositeUriComponentsContributor.class);
assertNotNull(uriComponentsContributor);
}
@Test(expected=TypeMismatchException.class)

View File

@@ -21,7 +21,6 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.Bean;
@@ -40,9 +39,8 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.method.support.CompositeUriComponentsContributor;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
@@ -54,11 +52,9 @@ import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExc
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.support.MvcUrls;
import org.springframework.web.util.UriComponents;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import static org.junit.Assert.*;
import static org.springframework.web.servlet.mvc.support.MvcUrlUtils.*;
/**
* A test fixture with an {@link WebMvcConfigurationSupport} instance.
@@ -159,19 +155,13 @@ public class WebMvcConfigurationSupportTests {
}
@Test
public void mvcUrls() throws Exception {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
try {
DateTime now = DateTime.now();
MvcUrls mvcUrls = this.wac.getBean(MvcUrls.class);
UriComponents uriComponents = mvcUrls.linkToMethodOn(controller(
TestController.class).methodWithTwoPathVariables(1, now));
public void uriComponentsContributor() throws Exception {
assertEquals("/foo/1/bar/" + ISODateTimeFormat.date().print(now), uriComponents.getPath());
}
finally {
RequestContextHolder.resetRequestAttributes();
}
CompositeUriComponentsContributor uriComponentsContributor = this.wac.getBean(
MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME,
CompositeUriComponentsContributor.class);
assertNotNull(uriComponentsContributor);
}
@Test

View File

@@ -14,12 +14,7 @@
* limitations under the License.
*/
package org.springframework.web.servlet.mvc.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
package org.springframework.web.servlet.mvc.method.annotation;
import org.hamcrest.Matchers;
import org.joda.time.DateTime;
@@ -38,142 +33,149 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.util.UriComponents;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.web.servlet.mvc.support.MvcUrlUtils.*;
import static org.junit.Assert.assertThat;
import static org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.mock;
/**
* Unit tests for {@link DefaultMvcUrls}.
* Unit tests for {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder}.
*
* @author Oliver Gierke
* @author Dietrich Schulten
* @author Rossen Stoyanchev
*/
public class DefaultMvcUrlsTests {
public class MvcUriComponentsContributorTests {
private MockHttpServletRequest request;
private MvcUrls mvcUrls;
private MvcUriComponentsBuilder builder;
@Before
public void setUp() {
this.request = new MockHttpServletRequest();
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(requestAttributes);
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(null, false));
this.mvcUrls = new DefaultMvcUrls(resolvers, null);
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(this.request));
}
@After
public void teardown() {
public void tearDown() {
RequestContextHolder.resetRequestAttributes();
}
@Test
public void linkToControllerRoot() {
UriComponents uriComponents = this.mvcUrls.linkToController(PersonControllerImpl.class).build();
public void fromController() {
UriComponents uriComponents = this.builder.fromController(PersonControllerImpl.class).build();
assertThat(uriComponents.toUriString(), Matchers.endsWith("/people"));
}
@Test
public void linkToParameterizedControllerRoot() {
UriComponents uriComponents = this.mvcUrls.linkToController(
PersonsAddressesController.class).buildAndExpand(15);
public void fromControllerUriTemplate() {
UriComponents uriComponents = this.builder.fromController(PersonsAddressesController.class).buildAndExpand(15);
assertThat(uriComponents.toUriString(), endsWith("/people/15/addresses"));
}
@Test
public void linkToMethodOnParameterizedControllerRoot() {
UriComponents uriComponents = this.mvcUrls.linkToMethodOn(
controller(PersonsAddressesController.class, 15).getAddressesForCountry("DE"));
assertThat(uriComponents.toUriString(), endsWith("/people/15/addresses/DE"));
}
@Test
public void linkToSubResource() {
public void fromControllerSubResource() {
UriComponents uriComponents =
this.mvcUrls.linkToController(PersonControllerImpl.class).pathSegment("something").build();
this.builder.fromController(PersonControllerImpl.class).pathSegment("something").build();
assertThat(uriComponents.toUriString(), endsWith("/people/something"));
}
@Test
public void linkToControllerWithMultipleMappings() {
UriComponents uriComponents = this.mvcUrls.linkToController(InvalidController.class).build();
public void fromControllerTwoTypeLevelMappings() {
UriComponents uriComponents = this.builder.fromController(InvalidController.class).build();
assertThat(uriComponents.toUriString(), is("http://localhost/persons"));
}
@Test
public void linkToControllerNotMapped() {
UriComponents uriComponents = this.mvcUrls.linkToController(UnmappedController.class).build();
public void fromControllerNotMapped() {
UriComponents uriComponents = this.builder.fromController(UnmappedController.class).build();
assertThat(uriComponents.toUriString(), is("http://localhost/"));
}
@Test
public void linkToMethodRefWithPathVar() throws Exception {
Method method = ControllerWithMethods.class.getDeclaredMethod("methodWithPathVariable", String.class);
UriComponents uriComponents = this.mvcUrls.linkToMethod(method, new Object[] { "1" });
public void fromMethodPathVariable() throws Exception {
UriComponents uriComponents = this.builder.fromMethodName(
ControllerWithMethods.class, "methodWithPathVariable", new Object[]{"1"}).build();
assertThat(uriComponents.toUriString(), is("http://localhost/something/1/foo"));
}
@Test
public void linkToMethodRefWithTwoPathVars() throws Exception {
public void fromMethodTypeLevelPathVariable() throws Exception {
this.request.setContextPath("/myapp");
UriComponents uriComponents = this.builder.fromMethodName(
PersonsAddressesController.class, "getAddressesForCountry", "DE").buildAndExpand("1");
assertThat(uriComponents.toUriString(), is("http://localhost/myapp/people/1/addresses/DE"));
}
@Test
public void fromMethodTwoPathVariables() throws Exception {
DateTime now = DateTime.now();
Method method = ControllerWithMethods.class.getDeclaredMethod(
"methodWithTwoPathVariables", Integer.class, DateTime.class);
UriComponents uriComponents = this.mvcUrls.linkToMethod(method, new Object[] { 1, now });
UriComponents uriComponents = this.builder.fromMethodName(
ControllerWithMethods.class, "methodWithTwoPathVariables", 1, now).build();
assertThat(uriComponents.getPath(), is("/something/1/foo/" + ISODateTimeFormat.date().print(now)));
}
@Test
public void linkToMethodRefWithPathVarAndRequestParam() throws Exception {
Method method = ControllerWithMethods.class.getDeclaredMethod("methodForNextPage", String.class, Integer.class, Integer.class);
UriComponents uriComponents = this.mvcUrls.linkToMethod(method, new Object[] {"1", 10, 5});
public void fromMethodWithPathVarAndRequestParam() throws Exception {
UriComponents uriComponents = this.builder.fromMethodName(
ControllerWithMethods.class, "methodForNextPage", "1", 10, 5).build();
assertThat(uriComponents.getPath(), is("/something/1/foo"));
MultiValueMap<String, String> queryParams = uriComponents.getQueryParams();
assertThat(queryParams.get("limit"), contains("5"));
assertThat(queryParams.get("offset"), contains("10"));
}
@Test
public void linkToMethod() {
UriComponents uriComponents = this.mvcUrls.linkToMethodOn(
controller(ControllerWithMethods.class).myMethod(null));
public void fromMethodNotMapped() throws Exception {
UriComponents uriComponents = this.builder.fromMethodName(UnmappedController.class, "unmappedMethod").build();
assertThat(uriComponents.toUriString(), is("http://localhost/"));
}
@Test
public void fromLastCall() {
UriComponents uriComponents = this.builder.fromLastCall(
mock(ControllerWithMethods.class).myMethod(null)).build();
assertThat(uriComponents.toUriString(), startsWith("http://localhost"));
assertThat(uriComponents.toUriString(), endsWith("/something/else"));
}
@Test
public void linkToMethodWithPathVar() {
UriComponents uriComponents = this.mvcUrls.linkToMethodOn(
controller(ControllerWithMethods.class).methodWithPathVariable("1"));
public void fromLastCallWithTypeLevelUriVars() {
UriComponents uriComponents = this.builder.fromLastCall(
mock(PersonsAddressesController.class).getAddressesForCountry("DE")).buildAndExpand(15);
assertThat(uriComponents.toUriString(), endsWith("/people/15/addresses/DE"));
}
@Test
public void fromLastCallWithPathVar() {
UriComponents uriComponents = this.builder.fromLastCall(
mock(ControllerWithMethods.class).methodWithPathVariable("1")).build();
assertThat(uriComponents.toUriString(), startsWith("http://localhost"));
assertThat(uriComponents.toUriString(), endsWith("/something/1/foo"));
}
@Test
public void linkToMethodWithPathVarAndRequestParams() {
UriComponents uriComponents = this.mvcUrls.linkToMethodOn(
controller(ControllerWithMethods.class).methodForNextPage("1", 10, 5));
public void fromLastCallWithPathVarAndRequestParams() {
UriComponents uriComponents = this.builder.fromLastCall(
mock(ControllerWithMethods.class).methodForNextPage("1", 10, 5)).build();
assertThat(uriComponents.getPath(), is("/something/1/foo"));
@@ -183,10 +185,10 @@ public class DefaultMvcUrlsTests {
}
@Test
public void linkToMethodWithPathVarAndMultiValueRequestParams() {
UriComponents uriComponents = this.mvcUrls.linkToMethodOn(
controller(ControllerWithMethods.class).methodWithMultiValueRequestParams(
"1", Arrays.asList(3, 7), 5));
public void fromLastCallWithPathVarAndMultiValueRequestParams() {
UriComponents uriComponents = this.builder.fromLastCall(
mock(ControllerWithMethods.class).methodWithMultiValueRequestParams(
"1", Arrays.asList(3, 7), 5)).build();
assertThat(uriComponents.getPath(), is("/something/1/foo"));
@@ -198,7 +200,7 @@ public class DefaultMvcUrlsTests {
@Test
public void usesForwardedHostAsHostIfHeaderIsSet() {
this.request.addHeader("X-Forwarded-Host", "somethingDifferent");
UriComponents uriComponents = this.mvcUrls.linkToController(PersonControllerImpl.class).build();
UriComponents uriComponents = this.builder.fromController(PersonControllerImpl.class).build();
assertThat(uriComponents.toUriString(), startsWith("http://somethingDifferent"));
}
@@ -206,7 +208,7 @@ public class DefaultMvcUrlsTests {
@Test
public void usesForwardedHostAndPortFromHeader() {
request.addHeader("X-Forwarded-Host", "foobar:8088");
UriComponents uriComponents = this.mvcUrls.linkToController(PersonControllerImpl.class).build();
UriComponents uriComponents = this.builder.fromController(PersonControllerImpl.class).build();
assertThat(uriComponents.toUriString(), startsWith("http://foobar:8088"));
}
@@ -214,7 +216,7 @@ public class DefaultMvcUrlsTests {
@Test
public void usesFirstHostOfXForwardedHost() {
request.addHeader("X-Forwarded-Host", "barfoo:8888, localhost:8088");
UriComponents uriComponents = this.mvcUrls.linkToController(PersonControllerImpl.class).build();
UriComponents uriComponents = this.builder.fromController(PersonControllerImpl.class).build();
assertThat(uriComponents.toUriString(), startsWith("http://barfoo:8888"));
}
@@ -254,6 +256,9 @@ public class DefaultMvcUrlsTests {
class UnmappedController {
@RequestMapping
public void unmappedMethod() {
}
}
@RequestMapping("/something")
@@ -287,4 +292,6 @@ public class DefaultMvcUrlsTests {
return null;
}
}
}

View File

@@ -1,122 +0,0 @@
/*
* Copyright 2012-2013 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.web.servlet.mvc.support;
import java.lang.reflect.Method;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.support.MvcUrlUtils.ControllerMethodValues;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Test fixture for {@link MvcUrlUtils}.
*
* @author Oliver Gierke
* @author Rossen Stoyanchev
*/
public class MvcUrlUtilsTests {
private MockHttpServletRequest request;
@Before
public void setUp() {
this.request = new MockHttpServletRequest();
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(requestAttributes);
}
@After
public void teardown() {
RequestContextHolder.resetRequestAttributes();
}
@Test
public void methodOn() {
HttpEntity<Void> result = MvcUrlUtils.controller(SampleController.class).someMethod(1L);
assertTrue(result instanceof ControllerMethodValues);
assertEquals("someMethod", ((ControllerMethodValues) result).getControllerMethod().getName());
}
@Test
public void typeLevelMapping() {
assertThat(MvcUrlUtils.getTypeLevelMapping(MyController.class), is("/type"));
}
@Test
public void typeLevelMappingNone() {
assertThat(MvcUrlUtils.getTypeLevelMapping(ControllerWithoutTypeLevelMapping.class), is("/"));
}
@Test
public void methodLevelMapping() throws Exception {
Method method = MyController.class.getMethod("method");
assertThat(MvcUrlUtils.getMethodMapping(method), is("/type/method"));
}
@Test
public void methodLevelMappingWithoutTypeLevelMapping() throws Exception {
Method method = ControllerWithoutTypeLevelMapping.class.getMethod("method");
assertThat(MvcUrlUtils.getMethodMapping(method), is("/method"));
}
@Test
public void methodMappingWithControllerMappingOnly() throws Exception {
Method method = MyController.class.getMethod("noMethodMapping");
assertThat(MvcUrlUtils.getMethodMapping(method), is("/type"));
}
@RequestMapping("/sample")
static class SampleController {
@RequestMapping("/{id}/foo")
HttpEntity<Void> someMethod(@PathVariable("id") Long id) {
return new ResponseEntity<Void>(HttpStatus.OK);
}
}
@RequestMapping("/type")
interface MyController {
@RequestMapping("/method")
void method();
@RequestMapping
void noMethodMapping();
}
interface ControllerWithoutTypeLevelMapping {
@RequestMapping("/method")
void method();
}
}