I am trying to build a navigation tree via recursion in JSF. I have defined a navigationNode
component as:
<composite:interface>
<composite:attribute name="node" />
</composite:interface>
<composite:implementation>
<ul>
<ui:repeat value="#{navigationTreeBean.getChildrenForNode(cc.attrs.node)}" var="child">
<li><navigation:navigationNode node="#{child}" /></li>
</ui:repeat>
</ul>
</composite:implementation>
My tree is declared as:
rootNode = new DefaultMutableTreeNode(new NodeData("Dashboard", "dashboard.xhtml"), true);
DefaultMutableTreeNode configurationsNode = new DefaultMutableTreeNode(new NodeData("Configurations", "configurations.xhtml"), true);
rootNode.add(configurationsNode);
I call component by:
<nav:navigationNode node="#{rootNode}" />
The problem is, this results in StackOverflowError
.
There are a few references to building recursion in JSF (for example, c:forEach vs ui:repeat in Facelets). The common problem seems to be mixing the build-time and render-time components/tags. In my case:
- My composite component is actually a tag, which is executed when the tree is built
- ui:repeat is an actual JSF component, which is evaluated when the tree is rendered
Is the child component navigation:navigationNode
actually processed before the ui:repeat
component? If so, what object is it using for #{child}
? Is it null (doesn't seem so)? Is the problem here that the child component is actually created without even caring about the ui:repeat and so each time a new child component is created even though it is not necessarily wanted?
The c:forEach vs ui:repeat in Facelets article has a separate section for this (recursion). The suggestion is to to use c:forEach
instead. I tried this, however it is still giving me the same StackOverflowError
, with different trace that I cannot make sense of.
I know that we can also build components by extending UIComponent
, but that approach (writing html in Java code) seems ugly. I would rather use MVC style / templates. However, if there are no other ways, do I have to implement this sort of recursion as UIComponent instead?