From 8f715a8547e7233a67fab15f56efe117911542b4 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 25 Aug 2014 16:12:03 -0400 Subject: [PATCH] Allow configuration of custom redirect patterns This change enables the ability to configure ViewNameMethodReturnValueHandler & ModelAndViewMethodReturnValueHandler with patterns to use to test for a custom redirect view name. Issue: SPR-12054 --- .../ModelAndViewMethodReturnValueHandler.java | 46 ++++++++++++++++++- .../ViewNameMethodReturnValueHandler.java | 33 ++++++++++++- ...lAndViewMethodReturnValueHandlerTests.java | 23 ++++++++-- ...ViewNameMethodReturnValueHandlerTests.java | 45 ++++++++++++------ 4 files changed, 126 insertions(+), 21 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java index cecae308fd..8c7ef7cce1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -17,6 +17,7 @@ package org.springframework.web.servlet.mvc.method.annotation; import org.springframework.core.MethodParameter; +import org.springframework.util.PatternMatchUtils; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; @@ -42,6 +43,32 @@ import org.springframework.web.servlet.View; */ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + private String[] redirectPatterns; + + + /** + * Configure one more simple patterns (as described in + * {@link org.springframework.util.PatternMatchUtils#simpleMatch}) to use in order to recognize + * custom redirect prefixes in addition to "redirect:". + * + *

Note that simply configuring this property will not make a custom + * redirect prefix work. There must be a custom View that recognizes the + * prefix as well. + * + * @since 4.1 + */ + public void setRedirectPatterns(String... redirectPatterns) { + this.redirectPatterns = redirectPatterns; + } + + /** + * The configured redirect patterns, if any. + */ + public String[] getRedirectPatterns() { + return this.redirectPatterns; + } + + @Override public boolean supportsReturnType(MethodParameter returnType) { return ModelAndView.class.isAssignableFrom(returnType.getParameterType()); @@ -62,7 +89,7 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); - if (viewName != null && viewName.startsWith("redirect:")) { + if (viewName != null && isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } @@ -78,4 +105,19 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn mavContainer.addAllAttributes(mav.getModel()); } + /** + * Whether the given view name is a redirect view reference. + * The default implementation checks the configured redirect patterns and + * also if the view name starts with the "redirect:" prefix. + * @param viewName the view name to check, never {@code null} + * @return "true" if the given view name is recognized as a redirect view + * reference; "false" otherwise. + */ + protected boolean isRedirectViewName(String viewName) { + if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) { + return true; + } + return viewName.startsWith("redirect:"); + } + } 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 d4ffdb8059..1397a595a3 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-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -17,6 +17,7 @@ package org.springframework.web.servlet.mvc.method.annotation; import org.springframework.core.MethodParameter; +import org.springframework.util.PatternMatchUtils; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; @@ -40,6 +41,31 @@ import org.springframework.web.servlet.RequestToViewNameTranslator; */ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + private String[] redirectPatterns; + + + /** + * Configure one more simple patterns (as described in + * {@link PatternMatchUtils#simpleMatch}) to use in order to recognize + * custom redirect prefixes in addition to "redirect:". + * + *

Note that simply configuring this property will not make a custom + * redirect prefix work. There must be a custom View that recognizes the + * prefix as well. + * + * @since 4.1 + */ + public void setRedirectPatterns(String... redirectPatterns) { + this.redirectPatterns = redirectPatterns; + } + + /** + * The configured redirect patterns, if any. + */ + public String[] getRedirectPatterns() { + return this.redirectPatterns; + } + @Override public boolean supportsReturnType(MethodParameter returnType) { Class paramType = returnType.getParameterType(); @@ -71,11 +97,16 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu /** * Whether the given view name is a redirect view reference. + * The default implementation checks the configured redirect patterns and + * also if the view name starts with the "redirect:" prefix. * @param viewName the view name to check, never {@code null} * @return "true" if the given view name is recognized as a redirect view * reference; "false" otherwise. */ protected boolean isRedirectViewName(String viewName) { + if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) { + return true; + } return viewName.startsWith("redirect:"); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java index 4929b4b728..b03160d127 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -104,7 +104,7 @@ public class ModelAndViewMethodReturnValueHandlerTests { } @Test - public void handleRedirectAttributesWithViewInstance() throws Exception { + public void handleRedirectAttributesWithViewName() throws Exception { RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap(); mavContainer.setRedirectModel(redirectAttributes); @@ -114,7 +114,22 @@ public class ModelAndViewMethodReturnValueHandlerTests { ModelMap model = mavContainer.getModel(); assertEquals("redirect:viewName", mavContainer.getViewName()); assertEquals("attrValue", model.get("attrName")); - assertSame("RedirectAttributes should be used if controller redirects", redirectAttributes, model); + assertSame(redirectAttributes, model); + } + + @Test + public void handleRedirectAttributesWithCustomPrefix() throws Exception { + RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap(); + mavContainer.setRedirectModel(redirectAttributes); + + ModelAndView mav = new ModelAndView("myRedirect:viewName", "attrName", "attrValue"); + handler.setRedirectPatterns("myRedirect:*"); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); + + ModelMap model = mavContainer.getModel(); + assertEquals("myRedirect:viewName", mavContainer.getViewName()); + assertEquals("attrValue", model.get("attrName")); + assertSame(redirectAttributes, model); } @Test @@ -137,10 +152,12 @@ public class ModelAndViewMethodReturnValueHandlerTests { return new MethodParameter(method, -1); } + @SuppressWarnings("unused") ModelAndView modelAndView() { return null; } + @SuppressWarnings("unused") String viewName() { return null; } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandlerTests.java index d5db099445..29fcbcfede 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ViewNameMethodReturnValueHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -20,7 +20,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import java.lang.reflect.Method; import org.junit.Before; import org.junit.Test; @@ -29,7 +28,6 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.ui.ModelMap; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler; import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap; /** @@ -45,23 +43,25 @@ public class ViewNameMethodReturnValueHandlerTests { private ServletWebRequest webRequest; + private MethodParameter param; + + @Before - public void setUp() { + public void setUp() throws NoSuchMethodException { this.handler = new ViewNameMethodReturnValueHandler(); this.mavContainer = new ModelAndViewContainer(); this.webRequest = new ServletWebRequest(new MockHttpServletRequest()); + this.param = new MethodParameter(getClass().getDeclaredMethod("viewName"), -1); } @Test public void supportsReturnType() throws Exception { - assertTrue(this.handler.supportsReturnType(createReturnValueParam("viewName"))); + assertTrue(this.handler.supportsReturnType(this.param)); } @Test public void returnViewName() throws Exception { - MethodParameter param = createReturnValueParam("viewName"); - this.handler.handleReturnValue("testView", param, this.mavContainer, this.webRequest); - + this.handler.handleReturnValue("testView", this.param, this.mavContainer, this.webRequest); assertEquals("testView", this.mavContainer.getViewName()); } @@ -69,18 +69,33 @@ public class ViewNameMethodReturnValueHandlerTests { public void returnViewNameRedirect() throws Exception { ModelMap redirectModel = new RedirectAttributesModelMap(); this.mavContainer.setRedirectModel(redirectModel); - MethodParameter param = createReturnValueParam("viewName"); - this.handler.handleReturnValue("redirect:testView", param, this.mavContainer, this.webRequest); - + this.handler.handleReturnValue("redirect:testView", this.param, this.mavContainer, this.webRequest); assertEquals("redirect:testView", this.mavContainer.getViewName()); - assertSame("Should have switched to the RedirectModel", redirectModel, this.mavContainer.getModel()); + assertSame(redirectModel, this.mavContainer.getModel()); + } + + @Test + public void returnViewCustomRedirect() throws Exception { + ModelMap redirectModel = new RedirectAttributesModelMap(); + this.mavContainer.setRedirectModel(redirectModel); + this.handler.setRedirectPatterns("myRedirect:*"); + this.handler.handleReturnValue("myRedirect:testView", this.param, this.mavContainer, this.webRequest); + assertEquals("myRedirect:testView", this.mavContainer.getViewName()); + assertSame(redirectModel, this.mavContainer.getModel()); } - private MethodParameter createReturnValueParam(String methodName) throws Exception { - Method method = getClass().getDeclaredMethod(methodName); - return new MethodParameter(method, -1); + @Test + public void returnViewRedirectWithCustomRedirectPattern() throws Exception { + ModelMap redirectModel = new RedirectAttributesModelMap(); + this.mavContainer.setRedirectModel(redirectModel); + this.handler.setRedirectPatterns("myRedirect:*"); + this.handler.handleReturnValue("redirect:testView", this.param, this.mavContainer, this.webRequest); + assertEquals("redirect:testView", this.mavContainer.getViewName()); + assertSame(redirectModel, this.mavContainer.getModel()); } + + @SuppressWarnings("unused") String viewName() { return null; }