I am trying to get the FacesContext
by calling FacesContext.getCurrentInstance()
in the run()
method of a Runnable
class, but it returns null
.
public class Task implements Runnable {
@Override
public void run() {
FacesContext context = FacesContext.getCurrentInstance(); // null!
// ...
}
}
How is this caused and how can I solve it?
The
FacesContext
is stored as aThreadLocal
variable in the thread responsible for the HTTP request which invoked theFacesServlet
, the one responsible for creating theFacesContext
. This thread usually goes through the JSF managed bean methods only. TheFacesContext
is not available in other threads spawned by that thread.You should actually also not have the need for it in other threads. Moreover, when your thread starts and runs independently, the underlying HTTP request will immediately continue processing the HTTP response and then disappear. You won't be able to do something with the HTTP response anyway.
You need to solve your problem differently. Ask yourself: what do you need it for? To obtain some information? Just pass that information to the
Runnable
during its construction instead.The below example assumes that you'd like to access some session scoped object in the thread.
If you however ultimately need to notify the client e.g. that the thread's work is finished, then you should be looking for a different solution than e.g. adding a faces message or so. The answer is to use "push". This can be achieved with SSE or websockets. A concrete websockets example can be found in this related question: Real time updates from database using JSF/Java EE. In case you happen to use PrimeFaces, look at
<p:push>
. In case you happen to use OmniFaces, look at<o:socket>
.Unrelated to the concrete problem, manually creating
Runnable
s and manually spawning threads in a Java EE web application is alarming. Head to the following Q&A to learn about all caveats and how it should actually be done: