Skip to content

Commit a2d3c27

Browse files
committed
Allow MVC handler methods to return any CharSequence type as view name
Issue: SPR-13165
1 parent a5349eb commit a2d3c27

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/RedirectTests.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,16 +39,19 @@
3939
* Redirect scenarios including saving and retrieving flash attributes.
4040
*
4141
* @author Rossen Stoyanchev
42+
* @author Juergen Hoeller
4243
*/
4344
public class RedirectTests {
4445

4546
private MockMvc mockMvc;
4647

48+
4749
@Before
4850
public void setup() {
4951
this.mockMvc = standaloneSetup(new PersonController()).build();
5052
}
5153

54+
5255
@Test
5356
public void save() throws Exception {
5457
this.mockMvc.perform(post("/persons").param("name", "Andy"))
@@ -60,6 +63,17 @@ public void save() throws Exception {
6063
.andExpect(flash().attribute("message", "success!"));
6164
}
6265

66+
@Test
67+
public void saveSpecial() throws Exception {
68+
this.mockMvc.perform(post("/people").param("name", "Andy"))
69+
.andExpect(status().isFound())
70+
.andExpect(redirectedUrl("/persons/Joe"))
71+
.andExpect(model().size(1))
72+
.andExpect(model().attributeExists("name"))
73+
.andExpect(flash().attributeCount(1))
74+
.andExpect(flash().attribute("message", "success!"));
75+
}
76+
6377
@Test
6478
public void saveWithErrors() throws Exception {
6579
this.mockMvc.perform(post("/persons"))
@@ -70,6 +84,16 @@ public void saveWithErrors() throws Exception {
7084
.andExpect(flash().attributeCount(0));
7185
}
7286

87+
@Test
88+
public void saveSpecialWithErrors() throws Exception {
89+
this.mockMvc.perform(post("/people"))
90+
.andExpect(status().isOk())
91+
.andExpect(forwardedUrl("persons/add"))
92+
.andExpect(model().size(1))
93+
.andExpect(model().attributeExists("person"))
94+
.andExpect(flash().attributeCount(0));
95+
}
96+
7397
@Test
7498
public void getPerson() throws Exception {
7599
this.mockMvc.perform(get("/persons/Joe").flashAttr("message", "success!"))
@@ -100,5 +124,16 @@ public String save(@Valid Person person, Errors errors, RedirectAttributes redir
100124
redirectAttrs.addFlashAttribute("message", "success!");
101125
return "redirect:/persons/{name}";
102126
}
127+
128+
@RequestMapping(value="/people", method=RequestMethod.POST)
129+
public Object saveSpecial(@Valid Person person, Errors errors, RedirectAttributes redirectAttrs) {
130+
if (errors.hasErrors()) {
131+
return "persons/add";
132+
}
133+
redirectAttrs.addAttribute("name", "Joe");
134+
redirectAttrs.addFlashAttribute("message", "success!");
135+
return new StringBuilder("redirect:").append("/persons").append("/{name}");
136+
}
103137
}
138+
104139
}

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

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,8 +24,9 @@
2424
import org.springframework.web.servlet.RequestToViewNameTranslator;
2525

2626
/**
27-
* Handles return values of types {@code void} and {@code String} interpreting
28-
* them as view name reference.
27+
* Handles return values of types {@code void} and {@code String} interpreting them
28+
* as view name reference. As of 4.2, it also handles general {@code CharSequence}
29+
* types, e.g. {@code StringBuilder} or Groovy's {@code GString}, as view names.
2930
*
3031
* <p>A {@code null} return value, either due to a {@code void} return type or
3132
* as the actual return value is left as-is allowing the configured
@@ -37,6 +38,7 @@
3738
* the handlers that support these annotations.
3839
*
3940
* @author Rossen Stoyanchev
41+
* @author Juergen Hoeller
4042
* @since 3.1
4143
*/
4244
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@@ -68,24 +70,21 @@ public String[] getRedirectPatterns() {
6870
@Override
6971
public boolean supportsReturnType(MethodParameter returnType) {
7072
Class<?> paramType = returnType.getParameterType();
71-
return (void.class == paramType || String.class == paramType);
73+
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
7274
}
7375

7476
@Override
7577
public void handleReturnValue(Object returnValue, MethodParameter returnType,
7678
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
7779

78-
if (returnValue == null) {
79-
return;
80-
}
81-
else if (returnValue instanceof String) {
82-
String viewName = (String) returnValue;
80+
if (returnValue instanceof CharSequence) {
81+
String viewName = returnValue.toString();
8382
mavContainer.setViewName(viewName);
8483
if (isRedirectViewName(viewName)) {
8584
mavContainer.setRedirectModelScenario(true);
8685
}
8786
}
88-
else {
87+
else if (returnValue != null){
8988
// should not happen
9089
throw new UnsupportedOperationException("Unexpected return type: " +
9190
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
@@ -101,10 +100,7 @@ else if (returnValue instanceof String) {
101100
* reference; "false" otherwise.
102101
*/
103102
protected boolean isRedirectViewName(String viewName) {
104-
if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) {
105-
return true;
106-
}
107-
return viewName.startsWith("redirect:");
103+
return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName) || viewName.startsWith("redirect:"));
108104
}
109105

110106
}

0 commit comments

Comments
 (0)