Skip to content

Commit fd97c8d

Browse files
committed
SPR-8770 Ensure RequestDataValueProcessor is invoked from RedirectView.
1 parent 2980ef4 commit fd97c8d

File tree

7 files changed

+135
-27
lines changed

7 files changed

+135
-27
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/RedirectView.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.springframework.util.CollectionUtils;
3939
import org.springframework.util.ObjectUtils;
4040
import org.springframework.util.StringUtils;
41+
import org.springframework.web.context.ContextLoader;
42+
import org.springframework.web.context.WebApplicationContext;
4143
import org.springframework.web.servlet.FlashMap;
4244
import org.springframework.web.servlet.HandlerMapping;
4345
import org.springframework.web.servlet.SmartView;
@@ -250,13 +252,7 @@ protected void renderMergedOutputModel(
250252

251253
String targetUrl = createTargetUrl(model, request);
252254

253-
if (getWebApplicationContext() != null) {
254-
RequestContext requestContext = createRequestContext(request, response, model);
255-
RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor();
256-
if (processor != null) {
257-
targetUrl = processor.processUrl(request, targetUrl);
258-
}
259-
}
255+
targetUrl = updateTargetUrl(targetUrl, model, request, response);
260256

261257
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
262258
if (!CollectionUtils.isEmpty(flashMap)) {
@@ -489,6 +485,35 @@ protected String urlEncode(String input, String encodingScheme) throws Unsupport
489485
return (input != null ? URLEncoder.encode(input, encodingScheme) : null);
490486
}
491487

488+
/**
489+
* Find the registered {@link RequestDataValueProcessor}, if any, and allow
490+
* it to update the redirect target URL.
491+
* @return the updated URL or the same as URL as the one passed in
492+
*/
493+
protected String updateTargetUrl(String targetUrl, Map<String, Object> model,
494+
HttpServletRequest request, HttpServletResponse response) {
495+
496+
RequestContext requestContext = null;
497+
if (getWebApplicationContext() != null) {
498+
requestContext = createRequestContext(request, response, model);
499+
}
500+
else {
501+
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
502+
if (wac != null && wac.getServletContext() != null) {
503+
requestContext = new RequestContext(request, response, wac.getServletContext(), model);
504+
}
505+
}
506+
507+
if (requestContext != null) {
508+
RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor();
509+
if (processor != null) {
510+
targetUrl = processor.processUrl(request, targetUrl);
511+
}
512+
}
513+
514+
return targetUrl;
515+
}
516+
492517
/**
493518
* Send a redirect back to the HTTP client
494519
* @param request current HTTP request (allows for reacting to request method)

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ protected View createView(String viewName, Locale locale) throws Exception {
389389
// Check for special "redirect:" prefix.
390390
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
391391
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
392-
return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
392+
RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
393+
return applyLifecycleMethods(viewName, view);
393394
}
394395
// Check for special "forward:" prefix.
395396
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
@@ -433,10 +434,14 @@ protected boolean canHandle(String viewName, Locale locale) {
433434
@Override
434435
protected View loadView(String viewName, Locale locale) throws Exception {
435436
AbstractUrlBasedView view = buildView(viewName);
436-
View result = (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
437+
View result = applyLifecycleMethods(viewName, view);
437438
return (view.checkResource(locale) ? result : null);
438439
}
439440

441+
private View applyLifecycleMethods(String viewName, AbstractView view) {
442+
return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
443+
}
444+
440445
/**
441446
* Creates a new View instance of the specified view class and configures it.
442447
* Does <i>not</i> perform any lookup for pre-defined View instances.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.web.servlet.tags.form;
17+
package org.springframework.web.servlet.support;
1818

1919
import java.util.Map;
2020

2121
import javax.servlet.http.HttpServletRequest;
2222

2323
import org.springframework.web.servlet.support.RequestDataValueProcessor;
2424

25-
class DelegatingRequestDataValueProcessor implements RequestDataValueProcessor {
25+
public class RequestDataValueProcessorWrapper implements RequestDataValueProcessor {
2626

2727
private RequestDataValueProcessor processor;
2828

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/AbstractHtmlElementTagTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.validation.BindingResult;
3333
import org.springframework.validation.Errors;
3434
import org.springframework.web.context.support.StaticWebApplicationContext;
35+
import org.springframework.web.servlet.support.RequestDataValueProcessorWrapper;
3536
import org.springframework.web.servlet.support.JspAwareRequestContext;
3637
import org.springframework.web.servlet.support.RequestContext;
3738
import org.springframework.web.servlet.support.RequestContextUtils;
@@ -66,7 +67,7 @@ protected MockPageContext createAndPopulatePageContext() throws JspException {
6667
MockPageContext pageContext = createPageContext();
6768
MockHttpServletRequest request = (MockHttpServletRequest) pageContext.getRequest();
6869
StaticWebApplicationContext wac = (StaticWebApplicationContext) RequestContextUtils.getWebApplicationContext(request);
69-
wac.registerSingleton("requestDataValueProcessor", DelegatingRequestDataValueProcessor.class);
70+
wac.registerSingleton("requestDataValueProcessor", RequestDataValueProcessorWrapper.class);
7071
extendRequest(request);
7172
extendPageContext(pageContext);
7273
RequestContext requestContext = new JspAwareRequestContext(pageContext);
@@ -103,7 +104,7 @@ protected RequestDataValueProcessor getMockRequestDataValueProcessor() {
103104
RequestDataValueProcessor mockProcessor = createMock(RequestDataValueProcessor.class);
104105
ServletRequest request = getPageContext().getRequest();
105106
StaticWebApplicationContext wac = (StaticWebApplicationContext) RequestContextUtils.getWebApplicationContext(request);
106-
wac.getBean(DelegatingRequestDataValueProcessor.class).setRequestDataValueProcessor(mockProcessor);
107+
wac.getBean(RequestDataValueProcessorWrapper.class).setRequestDataValueProcessor(mockProcessor);
107108
return mockProcessor;
108109
}
109110

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolverTests.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616

1717
package org.springframework.web.servlet.view;
1818

19+
import static org.easymock.EasyMock.createMock;
20+
import static org.easymock.EasyMock.expect;
21+
import static org.easymock.EasyMock.replay;
22+
import static org.easymock.EasyMock.verify;
23+
import static org.junit.Assert.assertEquals;
24+
import static org.junit.Assert.assertNotNull;
25+
import static org.junit.Assert.assertNull;
26+
import static org.junit.Assert.assertSame;
27+
import static org.junit.Assert.assertTrue;
28+
1929
import java.util.ArrayList;
2030
import java.util.Arrays;
2131
import java.util.Collections;
@@ -28,7 +38,6 @@
2838
import org.junit.After;
2939
import org.junit.Before;
3040
import org.junit.Test;
31-
3241
import org.springframework.http.MediaType;
3342
import org.springframework.mock.web.MockHttpServletRequest;
3443
import org.springframework.mock.web.MockHttpServletResponse;
@@ -40,9 +49,6 @@
4049
import org.springframework.web.servlet.View;
4150
import org.springframework.web.servlet.ViewResolver;
4251

43-
import static org.easymock.EasyMock.*;
44-
import static org.junit.Assert.*;
45-
4652
/**
4753
* @author Arjen Poutsma
4854
*/
@@ -418,8 +424,14 @@ public void resolveViewNameRedirectView() throws Exception {
418424
request.addHeader("Accept", "application/json");
419425
request.setRequestURI("/test");
420426

427+
StaticWebApplicationContext webAppContext = new StaticWebApplicationContext();
428+
webAppContext.setServletContext(new MockServletContext());
429+
webAppContext.refresh();
430+
431+
UrlBasedViewResolver urlViewResolver = new InternalResourceViewResolver();
432+
urlViewResolver.setApplicationContext(webAppContext);
421433
ViewResolver xmlViewResolver = createMock(ViewResolver.class);
422-
viewResolver.setViewResolvers(Arrays.<ViewResolver>asList(xmlViewResolver, new UrlBasedViewResolver()));
434+
viewResolver.setViewResolvers(Arrays.<ViewResolver>asList(xmlViewResolver, urlViewResolver));
423435

424436
View xmlView = createMock("application_xml", View.class);
425437
View jsonView = createMock("application_json", View.class);
@@ -491,15 +503,14 @@ public void resolveViewNoMatchUseUnacceptableStatus() throws Exception {
491503

492504
@Test
493505
public void nestedViewResolverIsNotSpringBean() throws Exception {
506+
StaticWebApplicationContext webAppContext = new StaticWebApplicationContext();
507+
webAppContext.setServletContext(new MockServletContext());
508+
webAppContext.refresh();
509+
494510
InternalResourceViewResolver nestedResolver = new InternalResourceViewResolver();
511+
nestedResolver.setApplicationContext(webAppContext);
495512
nestedResolver.setViewClass(InternalResourceView.class);
496513
viewResolver.setViewResolvers(new ArrayList<ViewResolver>(Arrays.asList(nestedResolver)));
497-
498-
StaticWebApplicationContext appContext = new StaticWebApplicationContext();
499-
appContext.setServletContext(new MockServletContext());
500-
appContext.refresh();
501-
viewResolver.setApplicationContext(appContext);
502-
503514
viewResolver.setDefaultContentType(MediaType.TEXT_HTML);
504515

505516
String viewName = "view";

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,22 @@
3434

3535
import junit.framework.AssertionFailedError;
3636

37+
import org.easymock.EasyMock;
3738
import org.junit.Test;
3839
import org.springframework.beans.TestBean;
3940
import org.springframework.http.HttpStatus;
4041
import org.springframework.mock.web.MockHttpServletRequest;
4142
import org.springframework.mock.web.MockHttpServletResponse;
43+
import org.springframework.mock.web.MockServletContext;
4244
import org.springframework.ui.ModelMap;
45+
import org.springframework.web.context.ContextLoader;
46+
import org.springframework.web.context.support.StaticWebApplicationContext;
47+
import org.springframework.web.servlet.DispatcherServlet;
4348
import org.springframework.web.servlet.FlashMap;
4449
import org.springframework.web.servlet.FlashMapManager;
4550
import org.springframework.web.servlet.View;
51+
import org.springframework.web.servlet.support.RequestDataValueProcessorWrapper;
52+
import org.springframework.web.servlet.support.RequestDataValueProcessor;
4653
import org.springframework.web.util.WebUtils;
4754

4855
/**
@@ -118,8 +125,8 @@ public void flashMap() throws Exception {
118125
RedirectView rv = new RedirectView();
119126
rv.setUrl("http://url.somewhere.com/path");
120127
rv.setHttp10Compatible(false);
121-
MockHttpServletRequest request = new MockHttpServletRequest();
122-
MockHttpServletResponse response = new MockHttpServletResponse();
128+
HttpServletRequest request = new MockHttpServletRequest();
129+
HttpServletResponse response = new MockHttpServletResponse();
123130
FlashMap flashMap = new FlashMap();
124131
flashMap.put("successMessage", "yay!");
125132
request.setAttribute(FlashMapManager.OUTPUT_FLASH_MAP_ATTRIBUTE, flashMap);
@@ -131,6 +138,64 @@ public void flashMap() throws Exception {
131138
assertEquals("/path", flashMap.getTargetRequestPath());
132139
assertEquals(model, flashMap.getTargetRequestParams().toSingleValueMap());
133140
}
141+
142+
@Test
143+
public void updateTargetUrl() throws Exception {
144+
StaticWebApplicationContext wac = new StaticWebApplicationContext();
145+
wac.registerSingleton("requestDataValueProcessor", RequestDataValueProcessorWrapper.class);
146+
wac.setServletContext(new MockServletContext());
147+
wac.refresh();
148+
149+
RequestDataValueProcessor mockProcessor = createMock(RequestDataValueProcessor.class);
150+
wac.getBean(RequestDataValueProcessorWrapper.class).setRequestDataValueProcessor(mockProcessor);
151+
152+
RedirectView rv = new RedirectView();
153+
rv.setApplicationContext(wac); // Init RedirectView with WebAppCxt
154+
rv.setUrl("/path");
155+
156+
HttpServletRequest request = new MockHttpServletRequest();
157+
request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
158+
HttpServletResponse response = new MockHttpServletResponse();
159+
160+
EasyMock.expect(mockProcessor.processUrl(request, "/path")).andReturn("/path?key=123");
161+
EasyMock.replay(mockProcessor);
162+
163+
rv.render(new ModelMap(), request, response);
164+
165+
EasyMock.verify(mockProcessor);
166+
}
167+
168+
169+
@Test
170+
public void updateTargetUrlWithContextLoader() throws Exception {
171+
StaticWebApplicationContext wac = new StaticWebApplicationContext();
172+
wac.registerSingleton("requestDataValueProcessor", RequestDataValueProcessorWrapper.class);
173+
174+
MockServletContext servletContext = new MockServletContext();
175+
ContextLoader contextLoader = new ContextLoader(wac);
176+
contextLoader.initWebApplicationContext(servletContext);
177+
178+
try {
179+
RequestDataValueProcessor mockProcessor = createMock(RequestDataValueProcessor.class);
180+
wac.getBean(RequestDataValueProcessorWrapper.class).setRequestDataValueProcessor(mockProcessor);
181+
182+
RedirectView rv = new RedirectView();
183+
rv.setUrl("/path");
184+
185+
HttpServletRequest request = new MockHttpServletRequest();
186+
HttpServletResponse response = new MockHttpServletResponse();
187+
188+
EasyMock.expect(mockProcessor.processUrl(request, "/path")).andReturn("/path?key=123");
189+
EasyMock.replay(mockProcessor);
190+
191+
rv.render(new ModelMap(), request, response);
192+
193+
EasyMock.verify(mockProcessor);
194+
}
195+
finally {
196+
contextLoader.closeWebApplicationContext(servletContext);
197+
}
198+
}
134199

135200
@Test
136201
public void emptyMap() throws Exception {
@@ -296,7 +361,7 @@ protected Map<String, Object> queryProperties(Map<String, Object> model) {
296361
expectedUrlForEncoding = "/context" + expectedUrlForEncoding;
297362
expect(request.getContextPath()).andReturn("/context");
298363
}
299-
364+
300365
HttpServletResponse response = createMock("response", HttpServletResponse.class);
301366
expect(response.encodeRedirectURL(expectedUrlForEncoding)).andReturn(expectedUrlForEncoding);
302367
response.sendRedirect(expectedUrlForEncoding);

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ViewResolverTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ private void doTestUrlBasedViewResolverWithoutPrefixes(UrlBasedViewResolver vr)
158158
view = vr.resolveViewName("redirect:myUrl", Locale.getDefault());
159159
assertEquals("Correct view class", RedirectView.class, view.getClass());
160160
assertEquals("Correct URL", "myUrl", ((RedirectView) view).getUrl());
161+
assertSame("View not initialized as bean", wac, ((RedirectView) view).getApplicationContext());
161162

162163
view = vr.resolveViewName("forward:myUrl", Locale.getDefault());
163164
assertEquals("Correct view class", InternalResourceView.class, view.getClass());

0 commit comments

Comments
 (0)