1

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 with h:link using includeViewParams="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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Pavel S.
  • 1,202
  • 1
  • 13
  • 29

0 Answers0