Injecting FacesContext as managed property of session-scoped managed bean
-
16-06-2021 - |
Question
I had a request-scoped JSF 1.2 managed bean that I needed to refactor to session-scoped bean because it is doing some expensive operation on @PostConstruct
and that is being called multiple times which really needs to be done only once. The side effect of changing the scope to session is now I cannot inject FacesContext
anymore in faces-config.xml
by doing like this:
<managed-property>
<property-name>context</property-name>
<value>#{facesContext}</value>
</managed-property>
where I have
setContext(FacesContext ctx) {}
in my managed bean.
In one of my action methods I need the context to access ExternalContext
/HttpServletResponse
. I don't want to invoke
FacesContext.getCurrentInstance();
inside my action method but somehow call setContext(FacesContext ctx)
externally to allow isolation of context injection for ease of mocked testing. I tried putting the setContext()
inside the @PostConstruct
only to realize later that FacesContext
is a per request thing and my ExternalContext
was reset to null
once a new request is being submitted.
How could I call setContext(FacesContext ctx)
auto-magically every time I hit a new request although the managed bean itself is session scoped?
Solution
Keep your request scoped bean and inject the session scoped bean in it instead so that you can pass the FacesContext
to it in the @PostConstruct
of the request scoped bean. In the session scoped bean, perform lazy loading/executing.
E.g.
public class RequestBean {
private FacesContext context; // Managed property.
private SessionBean sessionBean; // Managed property.
@PostConstruct
public void init() {
sessionBean.init(context);
}
// ...
}
and
public class SessionBean {
private SomeObject initializedObject;
public void init(FacesContext context) {
if (initializedObject != null) {
return;
}
initializedObject = initializeObject(context);
}
// ...
}