diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
index e5679f1b7c4..11ec8651dab 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
@@ -42,6 +42,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.util.ReflectionUtils.MethodFilter;
+import org.springframework.validation.DataBinder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -257,13 +258,19 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda
}
/**
- * Specify a WebBindingInitializer which will apply pre-configured
- * configuration to every DataBinder that this controller uses.
+ * Set a WebBindingInitializer to apply configure every DataBinder instance this controller uses.
*/
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
this.webBindingInitializer = webBindingInitializer;
}
+ /**
+ * Return the WebBindingInitializer which applies pre-configured configuration to {@link DataBinder} instances.
+ */
+ public WebBindingInitializer getWebBindingInitializer() {
+ return webBindingInitializer;
+ }
+
/**
* Specify the strategy to store session attributes with.
*
Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java
index 8f96204952b..4c19f4d218f 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java
@@ -17,12 +17,17 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.util.List;
+import java.util.Map;
+import org.springframework.beans.MutablePropertyValues;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.method.annotation.InitBinderMethodDataBinderFactory;
import org.springframework.web.method.support.InvocableHandlerMethod;
+import org.springframework.web.servlet.HandlerMapping;
/**
* An {@link InitBinderMethodDataBinderFactory} that creates a {@link ServletRequestDataBinder}.
@@ -47,7 +52,30 @@ public class ServletInitBinderMethodDataBinderFactory extends InitBinderMethodDa
*/
@Override
protected WebDataBinder createBinderInstance(Object target, String objectName) {
- return new ServletRequestDataBinder(target, objectName);
+ return new ServletRequestPathVarDataBinder(target, objectName);
}
-}
+ /**
+ * Adds URI template variables to the map of request values used to do data binding.
+ */
+ private static class ServletRequestPathVarDataBinder extends ServletRequestDataBinder {
+
+ public ServletRequestPathVarDataBinder(Object target, String objectName) {
+ super(target, objectName);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void doBind(MutablePropertyValues mpvs) {
+ RequestAttributes requestAttrs = RequestContextHolder.getRequestAttributes();
+ if (requestAttrs != null) {
+ String key = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
+ int scope = RequestAttributes.SCOPE_REQUEST;
+ Map uriTemplateVars = (Map) requestAttrs.getAttribute(key, scope);
+ mpvs.addPropertyValues(uriTemplateVars);
+ }
+ super.doBind(mpvs);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactoryTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactoryTests.java
new file mode 100644
index 00000000000..37bd0b50227
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactoryTests.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2011 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.mvc.method.annotation;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.TestBean;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.bind.ServletRequestDataBinder;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.servlet.HandlerMapping;
+
+/**
+ * Test fixture with {@link ServletInitBinderMethodDataBinderFactory}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class ServletInitBinderMethodDataBinderFactoryTests {
+
+ private ServletInitBinderMethodDataBinderFactory binderFactory;
+
+ private MockHttpServletRequest request;
+
+ private NativeWebRequest webRequest;
+
+ @Before
+ public void setup() {
+ binderFactory = new ServletInitBinderMethodDataBinderFactory(null, null);
+ request = new MockHttpServletRequest();
+ webRequest = new ServletWebRequest(request);
+ RequestContextHolder.setRequestAttributes(webRequest);
+ }
+
+ @After
+ public void teardown() {
+ RequestContextHolder.resetRequestAttributes();
+ }
+
+ @Test
+ public void createBinder() throws Exception {
+ Map uriTemplateVars = new HashMap();
+ uriTemplateVars.put("name", "nameValue");
+ uriTemplateVars.put("age", "25");
+ request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);
+
+ TestBean target = new TestBean();
+ WebDataBinder binder = binderFactory.createBinder(webRequest, target, "");
+ ((ServletRequestDataBinder) binder).bind(request);
+
+ assertEquals("nameValue", target.getName());
+ assertEquals(25, target.getAge());
+ }
+
+}
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/InitBinderMethodDataBinderFactory.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/InitBinderMethodDataBinderFactory.java
index bcc7ef3b88e..548ca7d0e4c 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/InitBinderMethodDataBinderFactory.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/InitBinderMethodDataBinderFactory.java
@@ -16,6 +16,7 @@
package org.springframework.web.method.annotation;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -41,13 +42,13 @@ public class InitBinderMethodDataBinderFactory extends DefaultDataBinderFactory
/**
* Create an {@code InitBinderMethodDataBinderFactory} instance with the given {@link InitBinder} methods.
- * @param initBinderMethods {@link InitBinder} methods to use to invoke to initialize new data binder instances
+ * @param binderMethods {@link InitBinder} methods to use to invoke to initialize new data binder instances
* @param bindingInitializer a {@link WebBindingInitializer} to initialize new data binder instances with
*/
- public InitBinderMethodDataBinderFactory(List initBinderMethods,
+ public InitBinderMethodDataBinderFactory(List binderMethods,
WebBindingInitializer bindingInitializer) {
super(bindingInitializer);
- this.initBinderMethods = initBinderMethods;
+ this.initBinderMethods = (binderMethods != null) ? binderMethods : new ArrayList();
}
/**
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java
index 46e756a0fce..3ac47dc2c8a 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java
@@ -94,11 +94,11 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
if (binder.getTarget() != null) {
doBind(binder, webRequest);
- if (shouldValidate(parameter)) {
+ if (shouldValidate(binder, parameter)) {
binder.validate();
}
- if (failOnError(parameter) && binder.getBindingResult().hasErrors()) {
+ if (failOnError(binder, parameter) && binder.getBindingResult().hasErrors()) {
throw new BindException(binder.getBindingResult());
}
}
@@ -133,9 +133,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
}
/**
+ * Whether to validate the target object of the given {@link WebDataBinder} instance.
+ * @param binder the data binder containing the validation candidate
+ * @param parameter the method argument for which data binding is performed
* @return true if {@link DataBinder#validate()} should be invoked, false otherwise.
*/
- protected boolean shouldValidate(MethodParameter parameter) {
+ protected boolean shouldValidate(WebDataBinder binder, MethodParameter parameter) {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation annot : annotations) {
if ("Valid".equals(annot.annotationType().getSimpleName())) {
@@ -146,9 +149,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
}
/**
+ * Whether to raise a {@link BindException} in case of data binding or validation errors.
+ * @param binder the binder on which validation is to be invoked
+ * @param parameter the method argument for which data binding is performed
* @return true if the binding or validation errors should result in a {@link BindException}, false otherwise.
*/
- protected boolean failOnError(MethodParameter parameter) {
+ protected boolean failOnError(WebDataBinder binder, MethodParameter parameter) {
int i = parameter.getParameterIndex();
Class>[] paramTypes = parameter.getMethod().getParameterTypes();
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java b/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
index 315e5d4d493..77673fb164a 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
@@ -24,8 +24,8 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.support.BindingAwareModelMap;
/**
- * Provides access to the model and a place to record model and view related decisions to all
- * {@link HandlerMethodArgumentResolver}s and {@link HandlerMethodReturnValueHandler}s .
+ * Provides access to the model and a place to record model and view related decisions made by
+ * {@link HandlerMethodArgumentResolver}s or a {@link HandlerMethodReturnValueHandler}.
*
* In addition to storing model attributes and a view, the {@link ModelAndViewContainer} also provides
* a {@link #setResolveView(boolean)} flag, which can be used to request or bypass a view resolution phase.
diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessorTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessorTests.java
index 02eb152ae74..7d7b34b71c1 100644
--- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessorTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessorTests.java
@@ -132,14 +132,14 @@ public class ModelAttributeMethodProcessorTests {
@Test
public void shouldValidate() throws Exception {
- assertTrue(processor.shouldValidate(paramNamedValidModelAttr));
- assertFalse(processor.shouldValidate(paramNonSimpleType));
+ assertTrue(processor.shouldValidate(null, paramNamedValidModelAttr));
+ assertFalse(processor.shouldValidate(null, paramNonSimpleType));
}
@Test
public void failOnError() throws Exception {
- assertFalse("Shouldn't failOnError with BindingResult", processor.failOnError(paramNamedValidModelAttr));
- assertTrue("Should failOnError without BindingResult", processor.failOnError(paramNonSimpleType));
+ assertFalse("Shouldn't failOnError with BindingResult", processor.failOnError(null, paramNamedValidModelAttr));
+ assertTrue("Should failOnError without BindingResult", processor.failOnError(null, paramNonSimpleType));
}
@Test