Skip to content

Commit 8de34c6

Browse files
committed
SPR-6301 - Support @RequestHeader on HttpHeaders parameters
1 parent a62b413 commit 8de34c6

File tree

7 files changed

+131
-5
lines changed

7 files changed

+131
-5
lines changed

org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ public String[] getHeaderValues(String headerName) {
9696
return (!ObjectUtils.isEmpty(headerValues) ? headerValues : null);
9797
}
9898

99+
public Iterator<String> getHeaderNames() {
100+
return CollectionUtils.toIterator(getRequest().getPropertyNames());
101+
}
102+
99103
public String getParameter(String paramName) {
100104
return getRequest().getParameter(paramName);
101105
}

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.springframework.http.HttpOutputMessage;
6767
import org.springframework.http.HttpStatus;
6868
import org.springframework.http.MediaType;
69+
import org.springframework.http.HttpHeaders;
6970
import org.springframework.http.converter.HttpMessageConverter;
7071
import org.springframework.http.converter.HttpMessageNotReadableException;
7172
import org.springframework.http.converter.HttpMessageNotWritableException;
@@ -1134,6 +1135,31 @@ public void requestParamMap() throws Exception {
11341135
assertEquals("key1=[value1],key2=[value21,value22]", response.getContentAsString());
11351136
}
11361137

1138+
@Test
1139+
public void requestHeaderMap() throws Exception {
1140+
initServlet(RequestHeaderMapController.class);
1141+
1142+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/map");
1143+
request.addHeader("Content-Type", "text/html");
1144+
request.addHeader("Custom-Header", new String[]{"value21", "value22"});
1145+
MockHttpServletResponse response = new MockHttpServletResponse();
1146+
1147+
servlet.service(request, response);
1148+
assertEquals("Content-Type=text/html,Custom-Header=value21", response.getContentAsString());
1149+
1150+
request.setRequestURI("/multiValueMap");
1151+
response = new MockHttpServletResponse();
1152+
1153+
servlet.service(request, response);
1154+
assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString());
1155+
1156+
request.setRequestURI("/httpHeaders");
1157+
response = new MockHttpServletResponse();
1158+
1159+
servlet.service(request, response);
1160+
assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString());
1161+
}
1162+
11371163

11381164
/*
11391165
* Controllers
@@ -1965,6 +1991,48 @@ public void multiValueMap(@RequestParam MultiValueMap<String, String> params, Wr
19651991
}
19661992
}
19671993
}
1968-
1994+
1995+
@Controller
1996+
public static class RequestHeaderMapController {
1997+
1998+
@RequestMapping("/map")
1999+
public void map(@RequestHeader Map<String, String> headers, Writer writer) throws IOException {
2000+
for (Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator(); it.hasNext();) {
2001+
Map.Entry<String, String> entry = it.next();
2002+
writer.write(entry.getKey() + "=" + entry.getValue());
2003+
if (it.hasNext()) {
2004+
writer.write(',');
2005+
}
2006+
2007+
}
2008+
}
2009+
2010+
@RequestMapping("/multiValueMap")
2011+
public void multiValueMap(@RequestHeader MultiValueMap<String, String> headers, Writer writer) throws IOException {
2012+
for (Iterator<Map.Entry<String, List<String>>> it1 = headers.entrySet().iterator(); it1.hasNext();) {
2013+
Map.Entry<String, List<String>> entry = it1.next();
2014+
writer.write(entry.getKey() + "=[");
2015+
for (Iterator<String> it2 = entry.getValue().iterator(); it2.hasNext();) {
2016+
String value = it2.next();
2017+
writer.write(value);
2018+
if (it2.hasNext()) {
2019+
writer.write(',');
2020+
}
2021+
}
2022+
writer.write(']');
2023+
if (it1.hasNext()) {
2024+
writer.write(',');
2025+
}
2026+
}
2027+
}
2028+
2029+
@RequestMapping("/httpHeaders")
2030+
public void httpHeaders(@RequestHeader HttpHeaders headers, Writer writer) throws IOException {
2031+
assertEquals("Invalid Content-Type", new MediaType("text", "html"), headers.getContentType());
2032+
multiValueMap(headers, writer);
2033+
}
2034+
2035+
}
2036+
19692037

19702038
}

org.springframework.web/src/main/java/org/springframework/web/bind/annotation/RequestMapping.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,16 @@
7777
* <li>{@link RequestParam @RequestParam} annotated parameters for access to
7878
* specific Servlet/Portlet request parameters. Parameter values will be
7979
* converted to the declared method argument type. Additionally,
80-
* {@code RequestParam @RequestParam} can be used on a {@link java.util.Map Map} or
81-
* {@link org.springframework.util.MultiValueMap MultiValueMap} to gain access
82-
* to all request parameters.
80+
* {@code @RequestParam} can be used on a {@link java.util.Map Map&lt;String, String&gt;} or
81+
* {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;}
82+
* method parameter to gain access to all request parameters.
8383
* <li>{@link RequestHeader @RequestHeader} annotated parameters for access to
8484
* specific Servlet/Portlet request HTTP headers. Parameter values will be
85-
* converted to the declared method argument type.
85+
* converted to the declared method argument type. Additionally,
86+
* {@code @RequestHeader} can be used on a {@link java.util.Map Map&lt;String, String&gt;},
87+
* {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;}, or
88+
* {@link org.springframework.http.HttpHeaders HttpHeaders} method parameter to
89+
* gain access to all request headers.
8690
* <li>{@link RequestBody @RequestBody} annotated parameters for access to
8791
* the Servlet request HTTP contents. Parameter values will be
8892
* converted to the declared method argument type using

org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828
import java.util.Set;
2929
import java.util.LinkedHashMap;
30+
import java.util.Iterator;
3031

3132
import org.apache.commons.logging.Log;
3233
import org.apache.commons.logging.LogFactory;
@@ -41,6 +42,7 @@
4142
import org.springframework.core.annotation.AnnotationUtils;
4243
import org.springframework.http.HttpInputMessage;
4344
import org.springframework.http.MediaType;
45+
import org.springframework.http.HttpHeaders;
4446
import org.springframework.http.converter.HttpMessageConverter;
4547
import org.springframework.ui.ExtendedModelMap;
4648
import org.springframework.ui.Model;
@@ -457,11 +459,15 @@ private Map resolveRequestParamMap(Class<? extends Map> mapType, NativeWebReques
457459
}
458460
}
459461

462+
@SuppressWarnings("unchecked")
460463
private Object resolveRequestHeader(String headerName, boolean required, String defaultValue,
461464
MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
462465
throws Exception {
463466

464467
Class<?> paramType = methodParam.getParameterType();
468+
if (Map.class.isAssignableFrom(paramType)) {
469+
return resolveRequestHeaderMap((Class<? extends Map>) paramType, webRequest);
470+
}
465471
if (headerName.length() == 0) {
466472
headerName = getRequiredParameterName(methodParam);
467473
}
@@ -484,6 +490,34 @@ else if (required) {
484490
return binder.convertIfNecessary(headerValue, paramType, methodParam);
485491
}
486492

493+
private Map resolveRequestHeaderMap(Class<? extends Map> mapType, NativeWebRequest webRequest) {
494+
if (MultiValueMap.class.isAssignableFrom(mapType)) {
495+
MultiValueMap<String, String> result;
496+
if (HttpHeaders.class.isAssignableFrom(mapType)) {
497+
result = new HttpHeaders();
498+
} else {
499+
result = new LinkedMultiValueMap<String, String>();
500+
}
501+
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
502+
String headerName = iterator.next();
503+
for (String headerValue : webRequest.getHeaderValues(headerName)) {
504+
result.add(headerName, headerValue);
505+
}
506+
}
507+
return result;
508+
}
509+
else {
510+
Map<String, String> result = new LinkedHashMap<String, String>();
511+
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
512+
String headerName = iterator.next();
513+
String headerValue = webRequest.getHeader(headerName);
514+
result.put(headerName, headerValue);
515+
}
516+
return result;
517+
}
518+
}
519+
520+
487521
/**
488522
* Resolves the given {@link RequestBody @RequestBody} annotation.
489523
*/

org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ public String[] getHeaderValues(String headerName) {
7272
return getExternalContext().getRequestHeaderValuesMap().get(headerName);
7373
}
7474

75+
public Iterator<String> getHeaderNames() {
76+
return getExternalContext().getRequestHeaderMap().keySet().iterator();
77+
}
78+
7579
public String getParameter(String paramName) {
7680
return getExternalContext().getRequestParameterMap().get(paramName);
7781
}

org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ public String[] getHeaderValues(String headerName) {
102102
return (!ObjectUtils.isEmpty(headerValues) ? headerValues : null);
103103
}
104104

105+
@SuppressWarnings("unchecked")
106+
public Iterator<String> getHeaderNames() {
107+
return CollectionUtils.toIterator(getRequest().getHeaderNames());
108+
}
109+
105110
public String getParameter(String paramName) {
106111
return getRequest().getParameter(paramName);
107112
}

org.springframework.web/src/main/java/org/springframework/web/context/request/WebRequest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ public interface WebRequest extends RequestAttributes {
4747
*/
4848
String[] getHeaderValues(String headerName);
4949

50+
/**
51+
* Return a Iterator over request header names.
52+
* @see javax.servlet.http.HttpServletRequest#getHeaderNames()
53+
* @since 3.0
54+
*/
55+
Iterator<String> getHeaderNames();
56+
5057
/**
5158
* Return the request parameter of the given name, or <code>null</code> if none.
5259
* <p>Retrieves the first parameter value in case of a multi-value parameter.

0 commit comments

Comments
 (0)