Last night, I awoke at 3 a.m. wondering whether David Geary and I should have given more coverage to the JSF 2 flash in our Core JSF book revision. Here is why I think your time is better spent learning about other, more powerful constructs, together with some thoughts about CDI and REST.
JSF 2 introduces an EL variable flash
. Anything you set
persists for one post-redirect-get cycle. (In contrast, anything in the request
scope is gone after a redirect.) A typical use of the flash is for messages. A
managed bean method might put a message in the flash,
ExternalContext.getFlash().put("warning", "Your password is about to expire");
Then the message can be displayed on the next page as
#{flash.warning}
That's handy—the message survives one redirect, and then it is gone.
But it also points to a weakness of the flash. It doesn't really fit into
the managed bean model. Normally, I would put a message in a managed bean
object, without
using the JSF API. Then I'd use it as #{myPage.warning}
. In
the published uses of the flash, you always see unsightly code in which data
are shoveled in or out of the flash.
Of course, I'd want the myPage
bean to go away soon, and do so
automatically. Maybe a CDI FlashScope
is in order, so that I can
do
@Named @FlashScoped public class MyPage
There is a discussion about this on the Seam 3 board.
Similar to Rails, the JSF 2 flash allows you to keep an entry for another cycle, by using
#{flash.keep.key}
This way, you can carry data along a page flow. You can have a data entry page with
<h:inputTextArea value="#{flash.description}"/>
followed by a confirmation page with
#{flash.keep.description}
followed by another page that shovels the description into its final destination.
(When I first saw this, I stared at it for a long time, not being able to
figure out from the documentation
what was going on. I finally looked at the source
and found that the getValue
method has special handling for
flash.keep
. There is also special handling for
flash.now
, which apparently is just a synonym for
requestScope
, perhaps to make Rails developers feel at home?)
My head started hurting when I traced the behavior. It just doesn't feel like the JSF way. It seems to be so much easier to use CDI and have a
@Named @ConversationScoped Widget
with a description
property. Then I can use
#{widget.description}
and end the conversation when I no longer
need the widget
.
Not only is is mentally simpler, it also works better. If you use
flash
, and your user opens two browser windows, the two windows
interfere with another in ways that make my head hurt even more.
(NB. This morning, my wife checked our daughter's appointment on the Kaiser web site, and I mentally gasped when she opened another browser tab to check her own appointment at the same time, because, as she told me when I asked, the site is so slow. I wasn't sure if it was going to work, but it did. The site uses Struts, not JSF :-))
Another good option for a page flow is to turn inputs into view parameters of a request-scoped bean.
<f:metadata> <f:viewParam name="description" value="#{widget.description}"/> </f:metadata> ... <h:commandButton action="next?faces-redirect=true&includeViewParams=true"/>
(Don't ask why it is faces-redirect
but includeViewParams
...)
This is all very politically correct, with REST and PRG, and it is also easy to reason about the behavior of your app. Multiple browser windows work fine.
Which is better? The REST way is easy to understand. You post to the confirmation page, and then post the same data again to the final page. There is no server-side state, and that makes it easy to test each page in isolation. But it is pretty tedious if your page contains lots of inputs. CDI takes the opposite approach and embraces server-side state as something that is your friend, provided of course that it is properly managed.
It is nice to know that JSF 2 supports two good ways of managing
data in a page flow, both of which seem better than using the
flash
and are definitely worth learning. Is it worth figuring out
the innermost and undocumented secrets of the flash
? Maybe not?
JSF has more nooks and crannies than the Winchester Mystery
House, and I think the most effective way of using it is to stay away as
many of them as I can.