I'm playing with "stateless"/"transient" views in JSF and I noticed that invoking ExternalContext.redirect()
causes a new session to be created.
So, I dug into the Mojarra (2.2.15) code:
// -> com.sun.faces.context.ExternalContextImpl:653
public void redirect(String requestURI) throws IOException {
FacesContext ctx = FacesContext.getCurrentInstance();
doLastPhaseActions(ctx, true);
if (ctx.getPartialViewContext().isPartialRequest()) {
if (getSession(true) instanceof HttpSession &&
ctx.getResponseComplete()) {
throw new IllegalStateException();
}
PartialResponseWriter pwriter;
ResponseWriter writer = ctx.getResponseWriter();
if (writer instanceof PartialResponseWriter) {
pwriter = (PartialResponseWriter) writer;
} else {
pwriter = ctx.getPartialViewContext().getPartialResponseWriter();
}
setResponseContentType("text/xml");
setResponseCharacterEncoding("UTF-8");
addResponseHeader("Cache-Control", "no-cache");
// pwriter.writePreamble("<?xml version='1.0' encoding='UTF-8'?>\n");
pwriter.startDocument();
pwriter.redirect(requestURI);
pwriter.endDocument();
} else {
((HttpServletResponse) response).sendRedirect(requestURI);
}
ctx.responseComplete();
}
Note that this method is the same also on JSF-2.3 GitHub master, nevertheless the check is not present at all on MyFaces
I wonder why they included getSession(true) instanceof HttpSession
, it seems pointless to me.
Can anyone explain the reason why shuch a check is there?
This is indeed not the correct behavior. It should simply have checked if the response
is an instance of HttpServletResponse
. It should also have done that before invoking its sendRedirect()
method which in its current form could have thrown a ClassCastException
in a Portlet environment with a poorly implemented bridge.
Technical reason for the explicit instanceof
checks on javax.servlet.http.*
classes is because JSF is also available for a Portlet environment. There they use javax.portlet.*
API instead of javax.servlet.http.*
API. A well known example which you probably ever heard about is "Liferay".