I have an issue with understanding how flash works in the jsf lifecycle.
I am trying to redirect to a different page from a phase listener through a normal get request and at the same time adding a flash message(of course i have set the flah.keepmessage) to be displayed on the new page. But the message fails to show up. I know that something is wrong and will be grateful if anyone can kindly assist in implementing a better way (without filters please).
phaseredirect1.html
<h:body>
<f:view>
<f:phaseListener binding="#{testphase.testPL}"/>
<div>Testing Phases Redirect 1</div>
</f:view>
</h:body>
TestPhaseRedirect.java
@SessionScoped
@ManagedBean(name="testphase")
public class TestPhaseRedirect {
private PhaseListener testPL;
@PostConstruct
private void initializeVar(){
testPL = new PhaseListener() {
@Override
public void afterPhase(PhaseEvent event) {
}
@Override
public void beforePhase(PhaseEvent event) {
getFacesContext().addMessage(null, new FacesMessage("Faces Message: redirecting to page 2..."));
getExternalContext().getFlash().setKeepMessages(true);
ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler)getFacesContext().getApplication().getNavigationHandler();
nav.performNavigation("redirect-to-page2");
getFacesContext().responseComplete();
return;
}
@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
};
}
public PhaseListener getTestPL() {
return testPL;
}
}
phaseredirect2.html
<h:body>
<f:view>
<div style="width:400px;">
<p:messages autoUpdate="true" closable="true"/>
<p>Testing Phases Redirect 2</p>
<p> Did it display the message? </p>
</div>
</f:view>
</h:body>
faces config
<navigation-case>
<from-outcome>redirect-to-page2</from-outcome>
<to-view-id>/phaseredirect2.html</to-view-id>
<redirect />
</navigation-case>
Kindly correct me. Thank you so much.
During the render response phase, it's too late to create the flash scope. You need to do it at latest during invoke application phase. Basically, this problem has the same grounds as when doing so in a <f:event type="preRenderView">
as already answered in the following related questions:
In your particular case, you need a dummy view parameter so that the invoke action phase is triggered and then use the <f:event type="postInvokeAction">
(after having created the custom event yourself or having installed OmniFaces as per the answers on the abovelinked questions):
<f:metadata>
<f:viewParam name="dummy" />
<f:event type="postInvokeAction" listener="#{bean.init}" />
</f:metadata>
with
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Faces Message: redirecting to page 2..."));
context.getExternalContext().getFlash().setKeepMessages(true);
ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
nav.performNavigation("redirect-to-page2");
}
or if you've chosen for OmniFaces
public void init() {
Messages.addFlashGlobalInfo("Faces Message: redirecting to page 2...");
Faces.navigate("redirect-to-page2");
}