JSF 2 Partial Requests doesn't use FacesContext from the Factory
It seems like the partial requests don't use the faces context instances that are created by FacesContextFactory
implementations.
Here's the code in UIViewRoot#processDecodes
that indicates the same
if (context.getPartialViewContext().isPartialRequest() &&
!context.getPartialViewContext().isExecuteAll()) {
context.getPartialViewContext().processPa开发者_如何学Pythonrtial(PhaseId.APPLY_REQUEST_VALUES);
} else {
super.processDecodes(context);
}
It seems like the PartialViewContext stores the default FacesContextImpl implementation within it and uses it to call lifecycle methods. (Notice that the processPartial method doesn't take a context object, because it uses it own internally stored one)
Is this a bug or this code in there for a specific reason?
Thanks
FacesContext
instances are unique per thread, and The FacesServlet
creates a ThreadLocal<FacesContext>
on the beginning of the request while acquiring the FacesContext
(which is the contract of FacesContextFactory#getFacesContext)
and removes it on the end of the response associated with the HTTP servlet request (by calling the FacesContext#release
).
Whenever you do a FacesContext#getCurrentInstance()
in your JSF code, you'll always get the same instance throughout the entire HTTP servlet request/response processing.
About the method UIViewRoot#processDecodes
,I really don't see any line which probably can indicate that method uses it's own created instance rather than the passed one. Which line made you think that?
It can be seen in the FacesServlet#service
method that it creates the FacesContext
from The FacesContextFactory
, here is a excerpt from the FacesServlet#service
method which shows this -
// Acquire the FacesContext instance for this request
FacesContext context = facesContextFactory.getFacesContext
(servletConfig.getServletContext(), request, response, lifecycle);
// Execute the request processing lifecycle for this request
try {
...
} catch (FacesException e) {
...
}
finally {
// Release the FacesContext instance for this request
context.release();
}
Considering this, I don't feel UIViewRoot#processDecodes
can have the FacesContext
instance which is not from FacesContextFactory
.
Since you're saying - you have set some additional parameters to the FacesContext
which get returned from FacesContextFactory
, that means you have your own custom implementation of FacesContextFactory
, if this is the case then are you sure that your instance is injected in the FacesServlet
and not mojarra's com.sun.faces.context.FacesContextFactoryImpl
(if you're using mojarra)?
Here's how i got it to work. Below is the code in my custom faces context factory
public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle lifecycle) throws FacesException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
ExternalContextFactory externalContextFactory = (ExternalContextFactory) getFactory(FactoryFinder.EXTERNAL_CONTEXT_FACTORY);
ExternalContext externalContext = externalContextFactory.getExternalContext(context, request, response);
// CustomFacesContext extends from FacesContextImpl
CustomFacesContext facesContext = new CustomFacesContext(externalContext, lifecycle);
ExceptionHandlerFactory exceptionHandlerFactory = (ExceptionHandlerFactory) getFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY);
ExceptionHandler exceptionHandler = exceptionHandlerFactory.getExceptionHandler();
facesContext.setExceptionHandler(exceptionHandler);
}
精彩评论