Monday, 1 November 2010

Persisting ViewScoped beans across views in request

I came across this problem when trying to deal with view scoped beans that you want to reuse in a different view, i.e. after clicking next in a wizard like page.

This was originally Discussed Here (now removed since Oracle merged Sun's forums).

The View Scope
There is a a brief summary of it here: JSF 2.0 New Feature Preview Series (Part 5) EDR1 Potpourri.
Basically view scoped values are attached to the current viewId. Values for the view scoped variables are stored in the map returned by UIViewRoot.getViewMap(boolean). Which is great for when your accessing the same view. However, it is cleared when the view is changed (e.g. from a navigation result) FacesContext.setViewRoot(javax.faces.component.UIViewRoot)

However, the flash scope was designed seemingly to solve this very problem.

Using the Flash Scope
Here's a write up of the Understanding the JSF 2.0 Flash scope. There's also some caveats shown here: The benefits and pitfalls of @ViewScoped.
So the logical step is to try it, :
public String doIt() {
   FacesContext.getCurrentInstance().getExternalContext().getFlash().put("thisBean", this);   return "next";
However, after some poking around, I discovered you can't re-store in FlashScope as ManagedBeanELResolver is before ScopedAttributeELResolver in the expression language resolver chain. Meaning that if you have a view "view1" with bean name "viewScopeBean1" and want to use the exact same bean in "view2" with bean name "viewScopeBean2", you can't.
The most you can do is store whatever data you need in the flash scope, then in the @PostConstruct of the new bean, pull in the values you need. Not an elegant solution but I'm sure messing around with the ELResolver chain could also do it but then you run the risk of it breaking else where.