diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/RedirectTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/RedirectTests.java index a249ffbd95..645bd5b81d 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/RedirectTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/RedirectTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -39,16 +39,19 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; * Redirect scenarios including saving and retrieving flash attributes. * * @author Rossen Stoyanchev + * @author Juergen Hoeller */ public class RedirectTests { private MockMvc mockMvc; + @Before public void setup() { this.mockMvc = standaloneSetup(new PersonController()).build(); } + @Test public void save() throws Exception { this.mockMvc.perform(post("/persons").param("name", "Andy")) @@ -60,6 +63,17 @@ public class RedirectTests { .andExpect(flash().attribute("message", "success!")); } + @Test + public void saveSpecial() throws Exception { + this.mockMvc.perform(post("/people").param("name", "Andy")) + .andExpect(status().isFound()) + .andExpect(redirectedUrl("/persons/Joe")) + .andExpect(model().size(1)) + .andExpect(model().attributeExists("name")) + .andExpect(flash().attributeCount(1)) + .andExpect(flash().attribute("message", "success!")); + } + @Test public void saveWithErrors() throws Exception { this.mockMvc.perform(post("/persons")) @@ -70,6 +84,16 @@ public class RedirectTests { .andExpect(flash().attributeCount(0)); } + @Test + public void saveSpecialWithErrors() throws Exception { + this.mockMvc.perform(post("/people")) + .andExpect(status().isOk()) + .andExpect(forwardedUrl("persons/add")) + .andExpect(model().size(1)) + .andExpect(model().attributeExists("person")) + .andExpect(flash().attributeCount(0)); + } + @Test public void getPerson() throws Exception { this.mockMvc.perform(get("/persons/Joe").flashAttr("message", "success!")) @@ -100,5 +124,16 @@ public class RedirectTests { redirectAttrs.addFlashAttribute("message", "success!"); return "redirect:/persons/{name}"; } + + @RequestMapping(value="/people", method=RequestMethod.POST) + public Object saveSpecial(@Valid Person person, Errors errors, RedirectAttributes redirectAttrs) { + if (errors.hasErrors()) { + return "persons/add"; + } + redirectAttrs.addAttribute("name", "Joe"); + redirectAttrs.addFlashAttribute("message", "success!"); + return new StringBuilder("redirect:").append("/persons").append("/{name}"); + } } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandler.java index 14ad890d58..9601ce60e3 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -24,8 +24,9 @@ import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.RequestToViewNameTranslator; /** - * Handles return values of types {@code void} and {@code String} interpreting - * them as view name reference. + * Handles return values of types {@code void} and {@code String} interpreting them + * as view name reference. As of 4.2, it also handles general {@code CharSequence} + * types, e.g. {@code StringBuilder} or Groovy's {@code GString}, as view names. * *
A {@code null} return value, either due to a {@code void} return type or * as the actual return value is left as-is allowing the configured @@ -37,6 +38,7 @@ import org.springframework.web.servlet.RequestToViewNameTranslator; * the handlers that support these annotations. * * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 3.1 */ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler { @@ -68,24 +70,21 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu @Override public boolean supportsReturnType(MethodParameter returnType) { Class> paramType = returnType.getParameterType(); - return (void.class == paramType || String.class == paramType); + return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType)); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { - if (returnValue == null) { - return; - } - else if (returnValue instanceof String) { - String viewName = (String) returnValue; + if (returnValue instanceof CharSequence) { + String viewName = returnValue.toString(); mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } - else { + else if (returnValue != null){ // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); @@ -101,10 +100,7 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu * reference; "false" otherwise. */ protected boolean isRedirectViewName(String viewName) { - if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) { - return true; - } - return viewName.startsWith("redirect:"); + return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName) || viewName.startsWith("redirect:")); } }