Mr.J4mes
Mr.J4mes

Reputation: 9266

Redirecting in @PostConstruct method resulted in IllegalStateException

According to the answer of BalusC, I used

FacesContext.getCurrentInstance().getExternalContext().redirect(url);

in my @PostConstruct method to stop JSF from rendering the view and redirect users. However, when I try to run the code, I still ran into the java.lang.IllegalStateException exception at the above line.

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.IllegalStateException
    at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:524)
    at StudentManagedBean.CourseSummary.init(CourseSummary.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

UPDATE: I added the following line in my @PostConstruct method:

System.out.println("INIT " + FacesContext.getCurrentInstance().getExternalContext().isResponseCommitted());

and what I saw was INIT true. I wonder if the response is supposed to be committed BEFORE the @PostConstruct method is called?

I'd be very grateful if you could give me an advice.

Upvotes: 3

Views: 4739

Answers (2)

Mr.J4mes
Mr.J4mes

Reputation: 9266

As mentioned in my update, the following line printed INIT true:

System.out.println("INIT " + FacesContext.getCurrentInstance().getExternalContext().isResponseCommitted());

I finally found why the above situation occurred. On my page, before the ManagedBean X, which contains the redirect function, was referenced by UIComponent A, another ManagedBean Y was referenced beforehand by UIComponent B that is placed above UIComponent A in the page structure. As a consequence, the response was partially committed by ManagedBean Y, which makes it impossible for ManagedBean X to send a redirect request.

Upvotes: 3

maple_shaft
maple_shaft

Reputation: 10463

A redirect will not work here, because even though the response has been completed and finalized, JSF is not smart enough to avoid its typical routine of running through the lifecycle events anyway.

Instead you can try doing a Forward from a RequestDispatcher. A Forward is different from a redirect in the following ways:

  • Performed internally by the servlet
  • Browser is apathetic
  • original url stays intact

Here is some code that displays how this can be done...

RequestDispatcher dispatcher =
    ((ServletRequest) context.getExternalContext().getRequest())
    .getRequestDispatcher("/j_spring_security_logout");

try {
  dispatcher.forward((ServletRequest) context.getExternalContext().getRequest(),
  (ServletResponse) context.getExternalContext().getResponse());
} catch (ServletException e) {
  log.error("ServletException", e);
} catch (IOException e) {
  log.error("IOException", e);
}

By doing this you are ending the execution of the FacesServlet prematurely and forwarding it onto a different servlet altogether. I imagine that from this other servlet it might be possible to redirect to the desired location.

Upvotes: 2

Related Questions