9

For example I have a servlet code that sets attribute to a HttpServletRequest:

request.setAttribute("someValue", someValue());
        RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJsp.jsp");
        rd.forward(this.request, this.response);
        return;

How do I make sure that the code above is thread safe?

This is the stacktrace I am getting:

java.lang.NullPointerException
    at org.apache.catalina.connector.Request.notifyAttributeAssigned(Request.java:1552)
    at org.apache.catalina.connector.Request.access$000(Request.java:105)
    at org.apache.catalina.connector.Request$3.set(Request.java:3342)
    at org.apache.catalina.connector.Request.setAttribute(Request.java:1504)
    at org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:541)
    at org.apache.catalina.core.ApplicationHttpRequest.setAttribute(ApplicationHttpRequest.java:281)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:286)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:471)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:402)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:329)
    at com.mycompany.myapp.servlet.SomeServlet.doRequest(SomeServlet.java:103)
    at com.mycompany.myapp.servlet.SomeServlet.doGet(SomeServlet.java:159)
quarks
  • 33,478
  • 73
  • 290
  • 513

5 Answers5

12
rd.forward(this.request, this.response);

This (pun intented) suggests that you've assigned request and response as instance variables of a class. Your concrete problem in turn suggests that the instance of the class itself is not threadsafe.

Assuming that it's actually the servlet itself, then you've there the cause of your problem. Servlets are not threadsafe at all. There's only one instance of it been created during webapp's startup which is then shared across all requests applicationwide.

You should never assign request or session scoped data as an instance variable of the servlet. It would only be overriden whenever another HTTP request takes place at the same moment. That would make your code threadunsafe, as you encountered yourself.

Here's some code which illustrates that:

public class MyServlet extends HttpServlet {

    private Object thisIsNOTThreadSafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadSafe;

        thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
        thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
    } 
}

Assigning the HTTP request itself as instance variable of a servlet is actually an epic mistake. When user Y fires another request at the same time the servlet is dealing with the request of user X, then user X would instantly get the request and response objects of user Y at hands. This is definitely threadunsafe. The NPE is caused because the request is at that moment "finished" with processing for user Y and thus released/destroyed.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • +1. I'd say your right on the money. Totally missed the `this.request` nonsense. That would explain it. – Thilo Dec 20 '12 at 12:09
  • @balasC I have same issue, Can you please review It http://stackoverflow.com/questions/28044187/struts2-execandwait-nullpointerexception – HybrisHelp Jan 20 '15 at 11:28
2

Request is thread safe by it's definition (unlike Session and ServletContext).

Regarding the exception: what Tomcat version are you using? This looks like a Tomcat bug.

Does the class that is the return type of someValue() method implement HttpAttributeBindingListener? And, can someValue() method return null? If both yes then the NullPointerException is obvious.

Igorry
  • 177
  • 3
  • 1
    Obvious? Really? How could a value be both `null` and implement something? – Thilo Dec 20 '12 at 11:54
  • The container expects a value of some type which may implement `ServletRequestAttributeListener`. And if an attribute does implement this interface then right after the attribute is attached to the request `ServletRequestAttributeListener.attributeAdded(...)` or `ServletRequestAttributeListener.attributeReplace(...)` called by the container. – Igorry Dec 20 '12 at 12:42
  • 1
    Setting `null` as attribute value is absolutely legit. So your "is obvious" argument has totally no grounds. As to the possible Tomcat bug, look in Tomcat source code before making such a dangerous statement. – BalusC Dec 20 '12 at 15:28
1

I'm not sure what this has to do with it being thread safe.

The exception you're getting is a NullPointerException it looks like Tomcat is trying to invoke a method on a null object.

In a Java web application each request has its own HttpServletRequest instance, so you can set the attributes on the request and be confident it is only for that user.

cowls
  • 24,013
  • 8
  • 48
  • 78
  • It's not his code trying to invoke a method on a null object, it's Tomcat internals. – Thilo Dec 20 '12 at 11:48
  • If you have explored Tomcat's source code then you'd have noticed that the method is trying to access a variable which was been released long before by end of HTTP request processing. This in turn suggests that another thread has released it and thus definitely a thread safety problem. – BalusC Dec 20 '12 at 15:26
1

use without this operator

     RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJsp.jsp");
    rd.forward(request, response);
    return;
Manish Nagar
  • 1,038
  • 7
  • 12
0

If you look at implementaion of request interface in tomcat it looks like below code.

public void setAttribute(String name, Object value) {

    // Name cannot be null
    if (name == null)
        throw new IllegalArgumentException
            (sm.getString("coyoteRequest.setAttribute.namenull"));

    // Null value is the same as removeAttribute()
    if (value == null) {
        removeAttribute(name);
        return;
    }

    if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
        internalDispatcherType = (DispatcherType)value;
        return;
    } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
        requestDispatcherPath = value;
        return;
    }

Its clearly seen that if key is null then it throw IllegalArgumentException but if value is null then it simply remove the key and old associated object with that key from reposatory. But if none of them is null them it will associate the object with that key and add them o repository.

It seems a temporary or tomcat issue.

for more on implementation refer to below link Source code of Request Implementation by tomcat

Rais Alam
  • 6,970
  • 12
  • 53
  • 84