Issue
I have my controller function setup like so
@RequestMapping(value = "/test/index.html", method = RequestMethod.GET)
public ModelAndView prepareView(HttpServletRequest request, @RequestHeader HttpHeaders header)
I was getting a null pointer exception from this at
org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver.resolveArgument(RequestHeaderMapMethodArgumentResolver.java:72)
so I decompiled this class file and stepped through in debug mode. The problematic section of the code looks like this:
/* 70 */ for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
/* 71 */ String headerName = (String)iterator.next();
/* 72 */ for (String headerValue : webRequest.getHeaderValues(headerName)) {
/* 73 */ result.add(headerName, headerValue);
/* */ }
/* */ }
webRequest
is an object of type NativeWebRequest
. So in line 70 I can see that webRequest.getHeaderNames()
is returning the
request headers i see in chrome network tab for example.
Apparently the load balancer (netscaler) is inserting some headers after the request is created (i'll call this x-model
) that I cannot see in chrome.
Following this trace I see all the standard RequestHeaders go through and be added with no issues (i.e Accept
, Cookie
, Host
, etc). However, eventually the iterator on line 70 reaches the x-model
header. Then in line 72, webRequest.getHeaderValues('x-model')
is called, and this returns null as there is no header called x-model is found. This causes a null pointer on the enhanced foreach.
Why is there a discrepancy between what is returned by ServletWebRequest.getHeaderNames()
and ServletWebRequest.getHeaderValues(headerName)
? What can I do to resolve this issue?
I have noticed that when I look at the iterator created in line 70, there is a keySet hashmap containing [cookie, connection, accept-language, host, accept, user-agent, accept-encoding, referer, x-model, x-tenant, upgrade-insecure-requests]
. However, the table entry does not contain an entry for x-model. Please see attached image for the 2 objects i refer to
I am using Java 7 and Spring 4.0.7
What is the difference between table and entryset here? Why does entryset contain the x-model
entry but table does not?
Solution
So the issue was actually because someone had added an override to HttpServletRequestWrapper.getHeaderNames()
which is what spring uses to retrieve the list of headernames to support a wrapper header which, but did not override HttpServletRequestWrapper.getHeaders()
which is what spring uses to find the value of the header
Answered By - Steven Hsu