diff --git a/build-spring-framework/resources/readme.txt b/build-spring-framework/resources/readme.txt index a959557bbfe..28ae6196db0 100644 --- a/build-spring-framework/resources/readme.txt +++ b/build-spring-framework/resources/readme.txt @@ -1,21 +1,28 @@ -SPRING FRAMEWORK 3.0.0 M1 () ----------------------------------- +SPRING FRAMEWORK 3.0 M1 (December 2008) +--------------------------------------- http://www.springframework.org 1. INTRODUCTION --------------- +This is the first milestone of Spring 3.0 which is scheduled for final release in Q2 2009. +This release updates the entire codebase for Java 5+ and introduces EL and REST support. + 2. RELEASE NOTES ---------------- +This release comes without reference documentation. For the time being, please consult +the provided javadoc for details on the new features. + 3. DISTRIBUTION JAR FILES ------------------------- +The Spring Framework module jar files can be found in the 'dist' directory. Note that +this release does not contain a 'spring.jar' file anymore. Furthermore, the jar file +names follow bundle repository conventions now. + 4. GETTING STARTED ------------------ -5. OBTAINING RELEASE JARS USING MAVEN OR IVY --------------------------------------------- - -6. ADDITIONAL RESOURCES ------------------------ +Check out the provided PetClinic sample application. It has been partially updated +for Spring 3.0 already. diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java index 08c4e397512..fe721beab78 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java @@ -23,6 +23,7 @@ import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; @@ -73,6 +74,16 @@ public class PortletWebRequest extends PortletRequestAttributes implements Nativ } + public String getHeader(String headerName) { + return getRequest().getProperty(headerName); + } + + @SuppressWarnings("unchecked") + public String[] getHeaderValues(String headerName) { + String[] headerValues = StringUtils.toStringArray(getRequest().getProperties(headerName)); + return (!ObjectUtils.isEmpty(headerValues) ? headerValues : null); + } + public String getParameter(String paramName) { return getRequest().getParameter(paramName); } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestHeader.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestHeader.java new file mode 100644 index 00000000000..4918166643c --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestHeader.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2008 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.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation which indicates that a method parameter should be bound to a web request header. + * Supported for {@link RequestMapping} annotated handler methods in Servlet and Portlet environments. + * + * @author Juergen Hoeller + * @since 3.0 + * @see RequestMapping + * @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter + * @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RequestHeader { + + /** + * The name of the request header to bind to. + */ + String value() default ""; + + /** + * Whether the header is required. + *

Default is true, leading to an exception thrown in case + * of the header missing in the request. Switch this to false + * if you prefer a null in case of the header missing. + *

Alternatively, provide a {@link #defaultValue() defaultValue}, + * which implicitely sets this flag to 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/RequestParam.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/RequestParam.java index 25a60947e72..69ba92bd56b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2008 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. @@ -23,33 +23,40 @@ 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 name of the request parameter to bind to. + */ String value() default ""; /** - * Whether the parameter is required.

Default is 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.

Alternatively, provide a {@link #defaultValue() defaultValue}, which implicitely sets this - * flag to false. + * Whether the parameter is required. + *

Default is 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. + *

Alternatively, provide a {@link #defaultValue() defaultValue}, + * which implicitely sets this flag to false. */ boolean required() default true; - /** The default value to use as a fallback. Supplying a default value implicitely sets {@link #required()} to false. */ + /** + * 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 3136f153994..3a4c4a962bc 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 @@ -46,6 +46,7 @@ import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.support.DefaultSessionAttributeStore; import org.springframework.web.bind.support.SessionAttributeStore; @@ -156,36 +157,47 @@ public class HandlerMethodInvoker { methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; - boolean paramRequired = false; - String paramDefaultValue = null; + String headerName = null; + boolean required = false; + String defaultValue = null; String pathVarName = null; String attrName = null; + int found = 0; Annotation[] paramAnns = methodParam.getParameterAnnotations(); for (Annotation paramAnn : paramAnns) { if (RequestParam.class.isInstance(paramAnn)) { RequestParam requestParam = (RequestParam) paramAnn; paramName = requestParam.value(); - paramRequired = requestParam.required(); - paramDefaultValue = requestParam.defaultValue(); - break; + required = requestParam.required(); + defaultValue = requestParam.defaultValue(); + found++; + } + else if (RequestHeader.class.isInstance(paramAnn)) { + RequestHeader requestHeader = (RequestHeader) paramAnn; + headerName = requestHeader.value(); + required = requestHeader.required(); + defaultValue = requestHeader.defaultValue(); + found++; } else if (ModelAttribute.class.isInstance(paramAnn)) { ModelAttribute attr = (ModelAttribute) paramAnn; attrName = attr.value(); + found++; } else if (PathVariable.class.isInstance(paramAnn)) { PathVariable pathVar = (PathVariable) paramAnn; pathVarName = pathVar.value(); + found++; } } - if ((paramName != null && attrName != null) || (paramName != null && pathVarName != null) || - (pathVarName != null && attrName != null)) { - throw new IllegalStateException("@RequestParam, @PathVariable and @ModelAttribute are exclusive " + - "choices - do not specify both on the same parameter: " + handlerMethod); + + if (found > 1) { + throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + + "do not specify more than one such annotation on the same parameter: " + handlerMethod); } - if (paramName == null && attrName == null && pathVarName == null) { + if (found == 0) { Object argValue = resolveCommonArgument(methodParam, webRequest); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; @@ -212,8 +224,10 @@ public class HandlerMethodInvoker { } if (paramName != null) { - args[i] = resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, - handler); + args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); + } + else if (headerName != null) { + args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); } else if (attrName != null) { WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); @@ -333,18 +347,13 @@ public class HandlerMethodInvoker { return initBinderArgs; } - private Object resolveRequestParam(String paramName, boolean paramRequired, String paramDefaultValue, + private Object resolveRequestParam(String paramName, boolean required, String defaultValue, MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { Class paramType = methodParam.getParameterType(); if (paramName.length() == 0) { - paramName = methodParam.getParameterName(); - if (paramName == null) { - throw new IllegalStateException( - "No parameter specified for @RequestParam argument of type [" + paramType.getName() + - "], and no parameter name information found in class file either."); - } + paramName = getRequiredParameterName(methodParam); } Object paramValue = null; if (webRequest.getNativeRequest() instanceof MultipartRequest) { @@ -357,23 +366,64 @@ public class HandlerMethodInvoker { } } if (paramValue == null) { - if (StringUtils.hasText(paramDefaultValue)) { - paramValue = paramDefaultValue; + if (StringUtils.hasText(defaultValue)) { + paramValue = defaultValue; } - else if (paramRequired) { + else if (required) { raiseMissingParameterException(paramName, paramType); } - 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."); - } + checkValue(paramName, paramValue, paramType); } WebDataBinder binder = createBinder(webRequest, null, paramName); initBinder(handlerForInitBinderCall, paramName, binder, webRequest); return binder.convertIfNecessary(paramValue, paramType, methodParam); } + private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (headerName.length() == 0) { + headerName = getRequiredParameterName(methodParam); + } + Object headerValue = null; + String[] headerValues = webRequest.getHeaderValues(headerName); + if (headerValues != null) { + headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); + } + if (headerValue == null) { + if (StringUtils.hasText(defaultValue)) { + headerValue = defaultValue; + } + else if (required) { + raiseMissingHeaderException(headerName, paramType); + } + checkValue(headerName, headerValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, headerName); + initBinder(handlerForInitBinderCall, headerName, binder, webRequest); + return binder.convertIfNecessary(headerValue, paramType, methodParam); + } + + private String getRequiredParameterName(MethodParameter methodParam) { + String name = methodParam.getParameterName(); + if (name == null) { + throw new IllegalStateException("No parameter name specified for argument of type [" + + methodParam.getParameterType().getName() + + "], and no parameter name information found in class file either."); + } + return name; + } + + private void checkValue(String name, Object value, Class paramType) { + if (value == null && paramType.isPrimitive()) { + throw new IllegalStateException("Optional " + paramType + " parameter '" + name + + "' 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."); + } + } + private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { @@ -471,6 +521,10 @@ public class HandlerMethodInvoker { throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); } + protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { + throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); + } + protected void raiseSessionRequiredException(String message) throws Exception { throw new IllegalStateException(message); } 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 d234cf1efa3..d0f532d5b37 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 @@ -63,6 +63,7 @@ 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; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -142,7 +143,7 @@ public class ServletAnnotationControllerTests { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("null", response.getContentAsString()); + assertEquals("null-null", response.getContentAsString()); } @Test @@ -161,7 +162,7 @@ public class ServletAnnotationControllerTests { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("foo", response.getContentAsString()); + assertEquals("foo-bar", response.getContentAsString()); } @Test @@ -281,9 +282,10 @@ public class ServletAnnotationControllerTests { request = new MockHttpServletRequest("GET", "/myPath2.do"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); + request.addHeader("header1", "10"); response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("test-value1-2", response.getContentAsString()); + assertEquals("test-value1-2-10", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath3.do"); request.addParameter("param1", "value1"); @@ -812,6 +814,7 @@ public class ServletAnnotationControllerTests { } } + /** @noinspection UnusedDeclaration*/ private static class BaseController { @@ -821,6 +824,7 @@ public class ServletAnnotationControllerTests { } } + @Controller private static class MyAdaptedController { @@ -830,10 +834,9 @@ public class ServletAnnotationControllerTests { } @RequestMapping("/myPath2.do") - public void myHandle(@RequestParam("param1")String p1, - @RequestParam("param2")int p2, - HttpServletResponse response) throws IOException { - response.getWriter().write("test-" + p1 + "-" + p2); + public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2, + @RequestHeader("header1") long h1, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + p2 + "-" + h1); } @RequestMapping("/myPath3") @@ -847,6 +850,7 @@ public class ServletAnnotationControllerTests { } } + @Controller @RequestMapping("/*.do") private static class MyAdaptedController2 { @@ -857,9 +861,9 @@ public class ServletAnnotationControllerTests { } @RequestMapping("/myPath2.do") - public void myHandle(@RequestParam("param1")String p1, int param2, HttpServletResponse response) - throws IOException { - response.getWriter().write("test-" + p1 + "-" + param2); + public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response, + @RequestHeader("header1") String h1) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2 + "-" + h1); } @RequestMapping("/myPath3") @@ -873,23 +877,26 @@ public class ServletAnnotationControllerTests { } } + @Controller private static class MyAdaptedControllerBase { @RequestMapping("/myPath2.do") - public void myHandle(@RequestParam("param1")T p1, int param2, HttpServletResponse response) throws IOException { - response.getWriter().write("test-" + p1 + "-" + param2); + public void myHandle(@RequestParam("param1") T p1, int param2, @RequestHeader Integer header1, + HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1); } @InitBinder - public void initBinder(@RequestParam("param1")T p1, int param2) { + public void initBinder(@RequestParam("param1") T p1, int param2) { } @ModelAttribute - public void modelAttribute(@RequestParam("param1")T p1, int param2) { + public void modelAttribute(@RequestParam("param1") T p1, int param2) { } } + @RequestMapping("/*.do") private static class MyAdaptedController3 extends MyAdaptedControllerBase { @@ -899,9 +906,9 @@ public class ServletAnnotationControllerTests { } @Override - public void myHandle(@RequestParam("param1")String p1, int param2, HttpServletResponse response) - throws IOException { - response.getWriter().write("test-" + p1 + "-" + param2); + public void myHandle(@RequestParam("param1") String p1, int param2, @RequestHeader Integer header1, + HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1); } @RequestMapping("/myPath3") @@ -916,15 +923,16 @@ public class ServletAnnotationControllerTests { @Override @InitBinder - public void initBinder(@RequestParam("param1")String p1, int param2) { + public void initBinder(@RequestParam("param1") String p1, int param2) { } @Override @ModelAttribute - public void modelAttribute(@RequestParam("param1")String p1, int param2) { + public void modelAttribute(@RequestParam("param1") String p1, int param2) { } } + @Controller @RequestMapping(method = RequestMethod.GET) private static class EmptyParameterListHandlerMethodController { @@ -941,6 +949,7 @@ public class ServletAnnotationControllerTests { } } + @Controller public static class MyFormController { @@ -961,6 +970,7 @@ public class ServletAnnotationControllerTests { } } + @Controller public static class MyModelFormController { @@ -981,14 +991,14 @@ public class ServletAnnotationControllerTests { } } + @Controller private static class MyCommandProvidingFormController extends MyFormController { @SuppressWarnings("unused") @ModelAttribute("myCommand") - private TestBean createTestBean(@RequestParam T defaultName, - Map model, - @RequestParam Date date) { + private TestBean createTestBean(@RequestParam T defaultName, Map model, + @RequestParam Date date) { model.put("myKey", "myOriginalValue"); return new TestBean(defaultName.getClass().getSimpleName() + ":" + defaultName.toString()); } @@ -1020,18 +1030,21 @@ public class ServletAnnotationControllerTests { } } + private static class MySpecialArg { public MySpecialArg(String value) { } } + @Controller private static class MyTypedCommandProvidingFormController extends MyCommandProvidingFormController { } + @Controller private static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { @@ -1045,13 +1058,14 @@ public class ServletAnnotationControllerTests { } } + @Controller private static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { @SuppressWarnings("unused") @InitBinder({"myCommand", "date"}) - private void initBinder(WebDataBinder binder, String date, @RequestParam("date")String[] date2) { + private void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) { assertEquals("2007-10-02", date); assertEquals(1, date2.length); assertEquals("2007-10-02", date2[0]); @@ -1061,6 +1075,7 @@ public class ServletAnnotationControllerTests { } } + private static class MyWebBindingInitializer implements WebBindingInitializer { public void initBinder(WebDataBinder binder, WebRequest request) { @@ -1071,6 +1086,7 @@ public class ServletAnnotationControllerTests { } } + private static class MySpecialArgumentResolver implements WebArgumentResolver { public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { @@ -1081,6 +1097,7 @@ public class ServletAnnotationControllerTests { } } + @Controller @RequestMapping("/myPath.do") private static class MyParameterDispatchingController { @@ -1126,12 +1143,14 @@ public class ServletAnnotationControllerTests { } } + @Controller @RequestMapping(value = "/*.do", method = RequestMethod.POST, params = "myParam=myValue") private static class MyPostMethodNameDispatchingController extends MethodNameDispatchingController { } + @Controller @RequestMapping("/myApp/*") private static class MyRelativePathDispatchingController { @@ -1157,6 +1176,7 @@ public class ServletAnnotationControllerTests { } } + @Controller private static class MyNullCommandController { @@ -1171,11 +1191,8 @@ public class ServletAnnotationControllerTests { } @RequestMapping("/myPath") - public void handle(@ModelAttribute TestBean testBean, - Errors errors, - @ModelAttribute TestPrincipal modelPrinc, - OtherPrincipal requestPrinc, - Writer writer) throws IOException { + public void handle(@ModelAttribute TestBean testBean, Errors errors, @ModelAttribute TestPrincipal modelPrinc, + OtherPrincipal requestPrinc, Writer writer) throws IOException { assertNull(testBean); assertNotNull(modelPrinc); assertNotNull(requestPrinc); @@ -1185,6 +1202,7 @@ public class ServletAnnotationControllerTests { } } + private static class TestPrincipal implements Principal { public String getName() { @@ -1192,6 +1210,7 @@ public class ServletAnnotationControllerTests { } } + private static class OtherPrincipal implements Principal { public String getName() { @@ -1199,6 +1218,7 @@ public class ServletAnnotationControllerTests { } } + private static class TestViewResolver implements ViewResolver { public View resolveViewName(final String viewName, Locale locale) throws Exception { @@ -1242,6 +1262,7 @@ public class ServletAnnotationControllerTests { } } + public static class ParentController { @RequestMapping(method = RequestMethod.GET) @@ -1249,44 +1270,51 @@ public class ServletAnnotationControllerTests { } } + @Controller @RequestMapping("/child/test") public static class ChildController extends ParentController { @RequestMapping(method = RequestMethod.GET) - public void doGet(HttpServletRequest req, HttpServletResponse resp, @RequestParam("childId")String id) { + public void doGet(HttpServletRequest req, HttpServletResponse resp, @RequestParam("childId") String id) { } } + @Controller public static class RequiredParamController { @RequestMapping("/myPath.do") - public void myHandle(@RequestParam(value = "id", required = true)String id) { - + public void myHandle(@RequestParam(value = "id", required = true) String id, + @RequestHeader(value = "header", required = true) String header) { } } + @Controller public static class OptionalParamController { @RequestMapping("/myPath.do") - public void myHandle(@RequestParam(value = "id", required = false)String id, HttpServletResponse response) + public void myHandle(@RequestParam(required = false) String id, + @RequestHeader(value = "header", required = false) String header, HttpServletResponse response) throws IOException { - response.getWriter().write(String.valueOf(id)); + response.getWriter().write(String.valueOf(id) + "-" + String.valueOf(header)); } } + @Controller public static class DefaultValueParamController { @RequestMapping("/myPath.do") - public void myHandle(@RequestParam(value = "id", defaultValue = "foo")String id, HttpServletResponse response) + public void myHandle(@RequestParam(value = "id", defaultValue = "foo") String id, + @RequestHeader(defaultValue = "bar") String header, HttpServletResponse response) throws IOException { - response.getWriter().write(String.valueOf(id)); + response.getWriter().write(String.valueOf(id) + "-" + String.valueOf(header)); } } + @Controller public static class MethodNotAllowedController { @@ -1318,5 +1346,4 @@ public class ServletAnnotationControllerTests { } } - } diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java index a567d447eeb..86f51890067 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java @@ -51,6 +51,14 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb } + public String getHeader(String headerName) { + return getExternalContext().getRequestHeaderMap().get(headerName); + } + + public String[] getHeaderValues(String headerName) { + return getExternalContext().getRequestHeaderValuesMap().get(headerName); + } + public String getParameter(String paramName) { return getExternalContext().getRequestParameterMap().get(paramName); } diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java index d04d1b396bd..9be308e1959 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java @@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -78,6 +79,16 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ } + public String getHeader(String headerName) { + return getRequest().getHeader(headerName); + } + + @SuppressWarnings("unchecked") + public String[] getHeaderValues(String headerName) { + String[] headerValues = StringUtils.toStringArray(getRequest().getHeaders(headerName)); + return (!ObjectUtils.isEmpty(headerValues) ? headerValues : null); + } + public String getParameter(String paramName) { return getRequest().getParameter(paramName); } diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/WebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/WebRequest.java index 670be89b8d8..682435e9013 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/WebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/WebRequest.java @@ -31,6 +31,21 @@ import java.util.Map; */ public interface WebRequest extends RequestAttributes { + /** + * Return the request header of the given name, or null if none. + *

Retrieves the first header value in case of a multi-value header. + * @see javax.servlet.http.HttpServletRequest#getHeader(String) + */ + String getHeader(String headerName); + + /** + * Return the request header values for the given header name, + * or null if none. + *

A single-value header will be exposed as an array with a single element. + * @see javax.servlet.http.HttpServletRequest#getHeaders(String) + */ + String[] getHeaderValues(String headerName); + /** * Return the request parameter of the given name, or null if none. *

Retrieves the first parameter value in case of a multi-value parameter.