Thursday, 5 September 2013

Redirect to same webflow view state causes exception with nested composites

Redirect to same webflow view state causes exception with nested composites

Consider a simple page with an input text and some validation to it. The
page is included in a Spring webflow as a view state. On validation fail
the same view state needs to be redisplayed, including validation
messages. This works fine. Using a composite component that encapsulates
input and message also works fine.
However, using the same composite component inside another composite leads
to the following error:
FacesException: Cannot add the same component twice
This Exception stems from a method called handleAddRemoveWithAutoPrune,
which adds components to a dynamic action list and throws the error if a
component is supposed to be added a second time.
Here is an example to reproduce the behaviour:
JSF Page
<h:form id="form">
<h:inputText id="text" value="#{bean.someValue}" >
<f:validateLength maximum="3" />
</h:inputText>
<h:message for="text" />
<!-- This will work -->
<test:ccInner anything="Blubb" />
<!-- This will not work -->
<test:ccOuter id="outer" title="Outer Component">
<test:ccInner id="inner" anything="Inner Component" />
</test:ccOuter>
<h:commandButton id="button" type="submit" value="Submit"
action="#{bean.doStuff}" />
</h:form>
Components
Inner
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html">
<cc:interface>
<cc:attribute name="anything" />
</cc:interface>
<cc:implementation>
#{cc.attrs.anything}
</cc:implementation>
</html>
Outer
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html">
<cc:interface>
<cc:attribute name="title" />
</cc:interface>
<cc:implementation>
#{cc.attrs.title}
<cc:insertChildren />
</cc:implementation>
</html>
(Omitting the bean and flow definition. Plain standard stuff)
I looked into this for a while. Others who have similar problems usually
encounter it when using composites inside iterating components (e.g.
dataTable), hence components will be added dynamically on view creation
and view restoring. The problem then occurs on a postback to the same
view, see for example this ticket here. There, the error was caused by a
flaw in the original poster's encode methode, however, my components are
plain and simple, no custom Java behind, so this doesn't help me...
Nonetheless I found two work-arounds: As described in the Spring Webflows
documentation a webflow automatically performs a redirect when a
transition to the same view state occurs.
1) When turning off this behaviour by adding
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-attributes>
<webflow:redirect-in-same-state value="false"/>
</webflow:flow-execution-attributes>
</webflow:flow-executor>
to the webflow.xml the problem disappears. However, as the text advises,
the original redirect is desired behaviour to prevent double form
submission and notifications in some browsers such as chrome when hitting
F5 or using back/forward.
2) As the text describes, Ajax requests will not cause a redirect, so
adding <f:ajax execute="@form" render="@form" /> to the submit button will
also solve the problem. But do I really want to use Ajax for a submission
of the full form? It seems kind of nonsensical to me.
While this works for the moment, 1) has serious drawbacks and 2) makes
things a bit more complicated and may also not always be desirable. Thus,
I would rather solve the original issue (or first understand it, for that
matter). Also, if this is a problem in the underlying implementation it
might be good to file a bug report (if there isn't one already).

No comments:

Post a Comment