2

Is it possible to get HttpServletRequest from the ServletContext?

JohnWinter
  • 913
  • 4
  • 11
  • 21

1 Answers1

11

Is it possible to get HttpServletRequest from the ServletContext?

No.

The ServletContext represents the application. The application can cover many sessions and requests. But you can't get the "currently running" request or session via the ServletContext. Detail on how servlets and scopes work can be found in this related answer: How do servlets work? Instantiation, sessions, shared variables and multithreading.

You're unfortunately not clear on the concrete functional requirement where you need this solution. You apparently have a ServletContext at hands somehow in an instance of the class of interest, but not a HttpServletRequest. It's hard to propose an answer showing the right way how to grab the HttpServletRequest in an instance of such class anyway. Decent MVC frameworks like JSF and Spring MVC have ways to grab the HttpServletRequest associated with the current thread in any class you want.

In case you're not using a MVC framework and thus can't use its facilities, then you can achieve this manually by storing the request (and response) as a ThreadLocal<T> in the current thread via a servlet filter.

Here's a kickoff example how such a thread local context class can look like:

public final class YourContext implements AutoCloseable {

    private static ThreadLocal<YourContext> instance = new ThreadLocal<>();

    private HttpServletRequest request;
    private HttpServletResponse response;

    private YourContext(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    public static YourContext create(HttpServletRequest request, HttpServletResponse response) {
        YourContext context = new YourContext(request, response);
        instance.set(context);
        return context;
    }

    public static YourContext getCurrentInstance() {
        return instance.get();
    }

    @Override    
    public void close() {
        instance.remove();
    }

    // ... (add methods here which return/delegate the request/response).    
}

You can create (and close!!) it in a servlet filter as below.

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    try (YourContext context = YourContext.create(request, response)) {
        chain.doFilter(request, response);
    }
}

Do note that closing is very important. Otherwise the thread will get polluted after it has done its job and will be recycled for a different request or even a completely different purpose. In case you aren't on Java 7 yet and thus can't use try-with-resources statement as above, then use a try-finally block.

Then, in any artifact which is invoked by the same thread/request (i.e. other filters, any servlets, any beans/classes (in)directly invoked by those artifacts, etc), you can obtain the HttpServletRequest associated with the current thread as below:

YourContext context = YourContext.getCurrentInstance();
HttpServletRequest request = context.getRequest();
// ...

Or, better create a delegate method, depending on whatever you'd like to do with the current request, such as obtaining the request locale:

YourContext context = YourContext.getCurrentInstance();
Locale requestLocale = context.getRequestLocale();
// ...

As a real world example, Java EE's MVC framework JSF offers exactly this possibility via FacesContext.

FacesContext context = FacesContext.getCurrentInstance();
Locale requestLocale = context.getExternalContext().getRequestLocale();
// ...
Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452