diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestParam.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestParam.java index 1f7ea2e9cf1..25a60947e72 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestParam.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestParam.java @@ -23,33 +23,33 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation which indicates that a method parameter should be bound - * to a web request parameter. Supported for {@link RequestMapping} - * annotated handler methods in Servlet and Portlet environments. + * Annotation which indicates that a method parameter should be bound to a web request parameter. Supported for {@link + * RequestMapping} annotated handler methods in Servlet and Portlet environments. * * @author Arjen Poutsma * @author Juergen Hoeller - * @since 2.5 * @see RequestMapping * @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter * @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter + * @since 2.5 */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestParam { - /** - * The request parameter to bind to. - */ + /** The request parameter to bind to. */ String value() default ""; /** - * Whether the parameter is required. - *
Default is Default is Alternatively, provide a {@link #defaultValue() defaultValue}, which implicitely sets this
+ * flag to Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
- * and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
+ * Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link
+ * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
*
* @author Juergen Hoeller
- * @since 2.5.2
+ * @author Arjen Poutsma
* @see #invokeHandlerMethod
+ * @since 2.5.2
*/
public class HandlerMethodInvoker {
- /**
- * We'll create a lot of these objects, so we don't want a new logger every time.
- */
+ /** We'll create a lot of these objects, so we don't want a new logger every time. */
private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class);
private final HandlerMethodResolver methodResolver;
@@ -86,7 +85,6 @@ public class HandlerMethodInvoker {
private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus();
-
public HandlerMethodInvoker(HandlerMethodResolver methodResolver) {
this(methodResolver, null);
}
@@ -95,10 +93,11 @@ public class HandlerMethodInvoker {
this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null);
}
- public HandlerMethodInvoker(
- HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer,
- SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer,
- WebArgumentResolver... customArgumentResolvers) {
+ public HandlerMethodInvoker(HandlerMethodResolver methodResolver,
+ WebBindingInitializer bindingInitializer,
+ SessionAttributeStore sessionAttributeStore,
+ ParameterNameDiscoverer parameterNameDiscoverer,
+ WebArgumentResolver... customArgumentResolvers) {
this.methodResolver = methodResolver;
this.bindingInitializer = bindingInitializer;
@@ -107,10 +106,10 @@ public class HandlerMethodInvoker {
this.customArgumentResolvers = customArgumentResolvers;
}
-
- public final Object invokeHandlerMethod(
- Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel)
- throws Exception {
+ public final Object invokeHandlerMethod(Method handlerMethod,
+ Object handler,
+ NativeWebRequest webRequest,
+ ExtendedModelMap implicitModel) throws Exception {
Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
try {
@@ -124,8 +123,10 @@ public class HandlerMethodInvoker {
Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args);
String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value();
if ("".equals(attrName)) {
- Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
- attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
+ Class resolvedType =
+ GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
+ attrName =
+ Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
}
implicitModel.addAttribute(attrName, attrValue);
}
@@ -142,9 +143,10 @@ public class HandlerMethodInvoker {
}
@SuppressWarnings("unchecked")
- private Object[] resolveHandlerArguments(
- Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel)
- throws Exception {
+ private Object[] resolveHandlerArguments(Method handlerMethod,
+ Object handler,
+ NativeWebRequest webRequest,
+ ExtendedModelMap implicitModel) throws Exception {
Class[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length];
@@ -155,6 +157,7 @@ public class HandlerMethodInvoker {
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
String paramName = null;
boolean paramRequired = false;
+ String paramDefaultValue = null;
String attrName = null;
Object[] paramAnns = methodParam.getParameterAnnotations();
@@ -164,6 +167,7 @@ public class HandlerMethodInvoker {
RequestParam requestParam = (RequestParam) paramAnn;
paramName = requestParam.value();
paramRequired = requestParam.required();
+ paramDefaultValue = requestParam.defaultValue();
break;
}
else if (ModelAttribute.class.isInstance(paramAnn)) {
@@ -204,7 +208,8 @@ public class HandlerMethodInvoker {
}
if (paramName != null) {
- args[i] = resolveRequestParam(paramName, paramRequired, methodParam, webRequest, handler);
+ args[i] = resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest,
+ handler);
}
else if (attrName != null) {
WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
@@ -238,7 +243,8 @@ public class HandlerMethodInvoker {
Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod);
String[] targetNames = AnnotationUtils.findAnnotation(methodToInvoke, InitBinder.class).value();
if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) {
- Object[] initBinderArgs = resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest);
+ Object[] initBinderArgs =
+ resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest);
if (debug) {
logger.debug("Invoking init-binder method: " + methodToInvoke);
}
@@ -253,8 +259,10 @@ public class HandlerMethodInvoker {
}
}
- private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod,
- WebDataBinder binder, NativeWebRequest webRequest) throws Exception {
+ private Object[] resolveInitBinderArguments(Object handler,
+ Method initBinderMethod,
+ WebDataBinder binder,
+ NativeWebRequest webRequest) throws Exception {
Class[] initBinderParams = initBinderMethod.getParameterTypes();
Object[] initBinderArgs = new Object[initBinderParams.length];
@@ -265,6 +273,7 @@ public class HandlerMethodInvoker {
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
String paramName = null;
boolean paramRequired = false;
+ String paramDefaultValue = null;
Object[] paramAnns = methodParam.getParameterAnnotations();
for (int j = 0; j < paramAnns.length; j++) {
@@ -273,6 +282,7 @@ public class HandlerMethodInvoker {
RequestParam requestParam = (RequestParam) paramAnn;
paramName = requestParam.value();
paramRequired = requestParam.required();
+ paramDefaultValue = requestParam.defaultValue();
break;
}
else if (ModelAttribute.class.isInstance(paramAnn)) {
@@ -302,16 +312,20 @@ public class HandlerMethodInvoker {
}
if (paramName != null) {
- initBinderArgs[i] = resolveRequestParam(paramName, paramRequired, methodParam, webRequest, null);
+ initBinderArgs[i] =
+ resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null);
}
}
return initBinderArgs;
}
- private Object resolveRequestParam(String paramName, boolean paramRequired,
- MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
- throws Exception {
+ private Object resolveRequestParam(String paramName,
+ boolean paramRequired,
+ String paramDefaultValue,
+ MethodParameter methodParam,
+ NativeWebRequest webRequest,
+ Object handlerForInitBinderCall) throws Exception {
Class paramType = methodParam.getParameterType();
if ("".equals(paramName)) {
@@ -332,10 +346,13 @@ public class HandlerMethodInvoker {
}
}
if (paramValue == null) {
- if (paramRequired) {
+ if (StringUtils.hasText(paramDefaultValue)) {
+ paramValue = paramDefaultValue;
+ }
+ else if (paramRequired) {
raiseMissingParameterException(paramName, paramType);
}
- if (paramType.isPrimitive()) {
+ if (paramValue == null && paramType.isPrimitive()) {
throw new IllegalStateException("Optional " + paramType + " parameter '" + paramName +
"' is not present but cannot be translated into a null value due to being declared as a " +
"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
@@ -346,8 +363,11 @@ public class HandlerMethodInvoker {
return binder.convertIfNecessary(paramValue, paramType, methodParam);
}
- private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
- ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
+ private WebDataBinder resolveModelAttribute(String attrName,
+ MethodParameter methodParam,
+ ExtendedModelMap implicitModel,
+ NativeWebRequest webRequest,
+ Object handler) throws Exception {
// Bind request parameter onto object...
String name = attrName;
@@ -374,9 +394,10 @@ public class HandlerMethodInvoker {
}
@SuppressWarnings("unchecked")
- public final void updateModelAttributes(
- Object handler, Map mavModel, ExtendedModelMap implicitModel, NativeWebRequest webRequest)
- throws Exception {
+ public final void updateModelAttributes(Object handler,
+ Map mavModel,
+ ExtendedModelMap implicitModel,
+ NativeWebRequest webRequest) throws Exception {
if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
@@ -407,8 +428,8 @@ public class HandlerMethodInvoker {
}
/**
- * Determine whether the given value qualifies as a "binding candidate",
- * i.e. might potentially be subject to bean-style data binding later on.
+ * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to
+ * bean-style data binding later on.
*/
protected boolean isBindingCandidate(Object value) {
return (value != null && !value.getClass().isArray() && !(value instanceof Collection) &&
@@ -426,7 +447,6 @@ public class HandlerMethodInvoker {
throw new IllegalStateException("Should never get here");
}
-
protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception {
throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]");
}
@@ -441,8 +461,7 @@ public class HandlerMethodInvoker {
return new WebRequestDataBinder(target, objectName);
}
- protected void doBind(NativeWebRequest webRequest, WebDataBinder binder, boolean failOnErrors)
- throws Exception {
+ protected void doBind(NativeWebRequest webRequest, WebDataBinder binder, boolean failOnErrors) throws Exception {
WebRequestDataBinder requestBinder = (WebRequestDataBinder) binder;
requestBinder.bind(webRequest);
@@ -475,8 +494,7 @@ public class HandlerMethodInvoker {
return value;
}
- protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest)
- throws Exception {
+ protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception {
if (WebRequest.class.isAssignableFrom(parameterType)) {
return webRequest;
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
index 78fb102d3ac..92492cd2c99 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
@@ -25,14 +25,14 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-import junit.framework.TestCase;
+import static org.junit.Assert.*;
+import org.junit.Test;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
@@ -55,6 +55,7 @@ import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
+import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -82,11 +83,11 @@ import org.springframework.web.util.NestedServletException;
* @author Sam Brannen
* @since 2.5
*/
-public class ServletAnnotationControllerTests extends TestCase {
+public class ServletAnnotationControllerTests {
- public void testStandardHandleMethod() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void standardHandleMethod() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class));
@@ -102,7 +103,61 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("test", response.getContentAsString());
}
- public void testProxiedStandardHandleMethod() throws Exception {
+ @Test(expected = MissingServletRequestParameterException.class)
+ public void requiredParamMissing() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(RequiredParamController.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ }
+
+ @Test
+ public void optionalParamMissing() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(OptionalParamController.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("null", response.getContentAsString());
+ }
+
+ @Test
+ public void defaultParamMissing() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(DefaultValueParamController.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("foo", response.getContentAsString());
+ }
+
+ @Test
+ public void proxiedStandardHandleMethod() throws Exception {
DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
@@ -110,7 +165,8 @@ public class ServletAnnotationControllerTests extends TestCase {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
- wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
+ wac.getBeanFactory()
+ .registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
wac.refresh();
return wac;
}
@@ -123,12 +179,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("test", response.getContentAsString());
}
- public void testEmptyParameterListHandleMethod() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void emptyParameterListHandleMethod() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(EmptyParameterListHandlerMethodController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(EmptyParameterListHandlerMethodController.class));
RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class);
vrDef.getPropertyValues().addPropertyValue("suffix", ".jsp");
wac.registerBeanDefinition("viewResolver", vrDef);
@@ -147,21 +204,23 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("", response.getContentAsString());
}
- public void testAdaptedHandleMethods() throws Exception {
+ @Test
+ public void adaptedHandleMethods() throws Exception {
doTestAdaptedHandleMethods(MyAdaptedController.class);
}
- public void testAdaptedHandleMethods2() throws Exception {
+ @Test
+ public void adaptedHandleMethods2() throws Exception {
doTestAdaptedHandleMethods(MyAdaptedController2.class);
}
- public void testAdaptedHandleMethods3() throws Exception {
+ @Test
+ public void adaptedHandleMethods3() throws Exception {
doTestAdaptedHandleMethods(MyAdaptedController3.class);
}
private void doTestAdaptedHandleMethods(final Class> controllerClass) throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass));
@@ -204,9 +263,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("test-name1-typeMismatch", response.getContentAsString());
}
- public void testFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void formController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class));
@@ -225,9 +284,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
}
- public void testModelFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void modelFormController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MyModelFormController.class));
@@ -246,7 +305,8 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
}
- public void testProxiedFormController() throws Exception {
+ @Test
+ public void proxiedFormController() throws Exception {
DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
@@ -255,7 +315,8 @@ public class ServletAnnotationControllerTests extends TestCase {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
- wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
+ wac.getBeanFactory()
+ .registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
wac.refresh();
return wac;
}
@@ -270,12 +331,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
}
- public void testCommandProvidingFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void commandProvidingFormController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MyCommandProvidingFormController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyCommandProvidingFormController.class));
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer());
@@ -295,16 +357,18 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
}
- public void testTypedCommandProvidingFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void typedCommandProvidingFormController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MyTypedCommandProvidingFormController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyTypedCommandProvidingFormController.class));
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer());
- adapterDef.getPropertyValues().addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver());
+ adapterDef.getPropertyValues()
+ .addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
wac.refresh();
return wac;
@@ -337,12 +401,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-special-99-special-99", response.getContentAsString());
}
- public void testBinderInitializingCommandProvidingFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void binderInitializingCommandProvidingFormController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class));
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
wac.refresh();
return wac;
@@ -359,12 +424,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
}
- public void testSpecificBinderInitializingCommandProvidingFormController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void specificBinderInitializingCommandProvidingFormController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class));
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
wac.refresh();
return wac;
@@ -381,12 +447,12 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
}
- public void testParameterDispatchingController() throws Exception {
+ @Test
+ public void parameterDispatchingController() throws Exception {
final MockServletContext servletContext = new MockServletContext();
final MockServletConfig servletConfig = new MockServletConfig(servletContext);
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.setServletContext(servletContext);
@@ -441,9 +507,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testMethodNameDispatchingController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void methodNameDispatchingController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class));
@@ -474,9 +540,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testMethodNameDispatchingControllerWithSuffix() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void methodNameDispatchingControllerWithSuffix() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class));
@@ -512,9 +578,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testControllerClassNamePlusMethodNameDispatchingController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void controllerClassNamePlusMethodNameDispatchingController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
RootBeanDefinition mapping = new RootBeanDefinition(ControllerClassNameHandlerMapping.class);
@@ -548,12 +614,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testPostMethodNameDispatchingController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void postMethodNameDispatchingController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MyPostMethodNameDispatchingController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyPostMethodNameDispatchingController.class));
wac.refresh();
return wac;
}
@@ -596,12 +663,13 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testRelativePathDispatchingController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void relativePathDispatchingController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
- wac.registerBeanDefinition("controller", new RootBeanDefinition(MyRelativePathDispatchingController.class));
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyRelativePathDispatchingController.class));
wac.refresh();
return wac;
}
@@ -629,9 +697,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("mySurpriseView", response.getContentAsString());
}
- public void testNullCommandController() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void nullCommandController() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MyNullCommandController.class));
@@ -648,9 +716,9 @@ public class ServletAnnotationControllerTests extends TestCase {
assertEquals("myView", response.getContentAsString());
}
- public void testEquivalentMappingsWithSameMethodName() throws Exception {
- @SuppressWarnings("serial")
- DispatcherServlet servlet = new DispatcherServlet() {
+ @Test
+ public void equivalentMappingsWithSameMethodName() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(ChildController.class));
@@ -672,128 +740,126 @@ public class ServletAnnotationControllerTests extends TestCase {
}
}
-
@RequestMapping("/myPath.do")
private static class MyController extends AbstractController {
- protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
response.getWriter().write("test");
return null;
}
}
-
private static class BaseController {
@RequestMapping(method = RequestMethod.GET)
- public void myPath2(HttpServletResponse response) throws IOException {
+ public void myPath2(HttpServletResponse response) throws IOException {
response.getWriter().write("test");
}
}
-
@Controller
private static class MyAdaptedController {
@RequestMapping("/myPath1.do")
- public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("test");
}
@RequestMapping("/myPath2.do")
- public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2, HttpServletResponse response) throws IOException {
+ public void myHandle(@RequestParam("param1")String p1,
+ @RequestParam("param2")int p2,
+ HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + p1 + "-" + p2);
}
@RequestMapping("/myPath3")
- public void myHandle(TestBean tb, HttpServletResponse response) throws IOException {
+ public void myHandle(TestBean tb, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge());
}
@RequestMapping("/myPath4.do")
- public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException {
+ public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode());
}
}
-
@Controller
@RequestMapping("/*.do")
private static class MyAdaptedController2 {
@RequestMapping
- public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("test");
}
@RequestMapping("/myPath2.do")
- public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response) throws IOException {
+ public void myHandle(@RequestParam("param1")String p1, int param2, HttpServletResponse response)
+ throws IOException {
response.getWriter().write("test-" + p1 + "-" + param2);
}
@RequestMapping("/myPath3")
- public void myHandle(TestBean tb, HttpServletResponse response) throws IOException {
+ public void myHandle(TestBean tb, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge());
}
@RequestMapping("/myPath4.*")
- public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException {
+ public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode());
}
}
-
@Controller
private static class MyAdaptedControllerBasetrue, leading to an exception thrown in case
- * of the parameter missing in the request. Switch this to false
- * if you prefer a null in case of the parameter missing.
+ * Whether the parameter is required. true, leading to an exception thrown in case of the
+ * parameter missing in the request. Switch this to false if you prefer a null in case of
+ * the parameter missing. false.
*/
boolean required() default true;
+ /** The default value to use as a fallback. Supplying a default value implicitely sets {@link #required()} to false. */
+ String defaultValue() default "";
+
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java
index 4e61fb2c46f..8e50de38d2e 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java
@@ -38,6 +38,7 @@ import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
@@ -56,22 +57,20 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartRequest;
/**
- * Support class for invoking an annotated handler method.
- * Operates on the introspection results of a {@link HandlerMethodResolver}
- * for a specific handler type.
+ * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link
+ * HandlerMethodResolver} for a specific handler type.
*
- *