I have 2 views (a.xhtml
and b.xhtml
) one of which contains a link to the other. The first view:
- uses the current view map by setting some value to it;
- points to
b.xhtml
withh:link
usingincludeViewParams="true"
in order to automatically include view parameters in the link's query string.
a.xhtml
:
<f:view >
<f:metadata>
<f:viewAction>
<!-- just set any value to force view map creation... -->
<f:setPropertyActionListener target="#{viewScope.username}" value="John" />
</f:viewAction>
</f:metadata>
<h:link id="alink" value="Go to B" outcome="b" includeViewParams="true" />
<h:form>
<h:commandButton id="away" action="b" value="Navigate away" immediate="false" />
</h:form>
</f:view>
</html>
and b.xhtml
:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view >
<f:metadata>
<f:viewParam id="id" name="userid" value="1" />
</f:metadata>
</f:view>
</html>
Also I am creating here a ViewMapListener
in order to demonstrate 'spurious' view map destruction event calls that happen once a.xhtml
gets visited. In my faces-config.xml
I'm having this entry:
<system-event-listener>
<system-event-listener-class>org.my.TestViewMapListener</system-event-listener-class>
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
where TestViewMapListener
is like this:
public class TestViewMapListener implements ViewMapListener {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if (event instanceof PreDestroyViewMapEvent) {
PreDestroyViewMapEvent viewMapEvent = (PreDestroyViewMapEvent)event;
UIViewRoot viewRoot = (UIViewRoot)viewMapEvent.getComponent();
System.out.println("PreDestroyViewMapEvent: "+viewRoot.getViewId());
}
}
...
Once the page a.xhtml
is rendered, the listener prints out the following line:
PreDestroyViewMapEvent: /b.xhtml
which is strange because b.xhtml
has never been visited. When I navigate away with "Navigate away"
button a correct event is printed as expected:
PreDestroyViewMapEvent: /a.xhtml
The incorrect event is fired only if I am using includeViewParams="true"
on the link. By debugging, I can see that it happens because com.sun.faces.application.view.ViewMetadataImpl.createMetadataView(FacesContext)
is temporarily setting to FacesContext
a UIViewRoot for b.xhtml
where a shallow copy of the original view map is created and set to temporary view root. This is probably done in order to correctly detect values of query string parameters for the link; it also temporarily turns off events for the time of the manipulations however it turns them back on too early (see 'finally' block), so view map destruction event is 'incorrectly' fired for a temporary copy of the view map, while no events for the original view map itself are expected at this time. It's a headache because I need to take some additional actions in order to detect whether it is the original map is destroyed or it is a spurious event for its 'ghost'.
Is this a bug or a desired behavior? I am using Mojarra 2.2.12.