So I have this very small JSF example:
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Index</title>
</h:head>
<h:body>
<h:form>
<h:commandButton action="#{reqScopedBackingBean.foo()}" value="Submit"/>
</h:form>
</h:body>
</html>
and the foo is implement as seen below:
package biz.tugay.jsftags;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
@ManagedBean
@RequestScoped
public class ReqScopedBackingBean {
public String foo() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("message", "Success!!");
return "hello?faces-redirect=true";
}
}
and finally hello.xhtml
is as follows:
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Hello</title>
</h:head>
<h:body>
<h:outputText value="#{flash.keep.message}"/>
</h:body>
</html>
in the above example, when I hit Submit, I will be redirected to hello.xhtml and see the "Success!!" text just fine. And when I refresh the page, I will still see the message because I am calling the keep method as seen below:
#{flash.keep.message}
Now moving on to another example:
index.xhtml and ReqScopedBackingBean are same, however this time hello.xhtml is as follows:
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Hello</title>
</h:head>
<h:body>
#{otherBean.pullValuesFromFlash()}
<h:outputText value="#{otherBean.message}"/>
</h:body>
</html>
and OtherBean.java
is as follows:
@ManagedBean
@RequestScoped
public class OtherBean {
private String message;
public void pullValuesFromFlash() {
final Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.keep("message");
final String message = (String) flash.get("message");
setMessage(message);
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I am expecting the behavior to be same with the first example. However, when I am on hello.xhtml, I will not see the success message. However, if I comment out the line:
// flash.keep("message");
then the message will appear(but refresh on hello.xhtml will not re-show the Success message as in the first example).
My question is, what is the difference here? How is
#{flash.keep.message}
and different than
flash.keep("message");
final String message = (String) flash.get("message");
?
You've hit a Mojarra bug of Flash#keep()
. Basically, Mojarra unnecessarily removes the entry from the current flash scope before putting it in the next flash scope.
It'll work if you reorder the logic as below.
public void pullValuesFromFlash() {
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
String message = (String) flash.get("message");
flash.keep("message");
setMessage(message);
}
I have fixed this bug as per issue 4167.
Unrelated to the concrete problem, those <h:outputText>
s are unnecessary. You can safely remove them to reduce boilerplate. See also Is it suggested to use h:outputText for everything?