Rectangle 27 0

java Recursion in JSF (c:forEach vs. ui:repeat)?


*  JSF Stuff
      o Chapter One
      o Chapter Two
            + Section A
            + Section B 
      o Chapter Three
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head><title>Facelet Tree</title></h:head>
  <h:body>
    <ul>
      <ui:repeat value="#{tree.treeNodes}" var="node">
        <h:outputText rendered="#{node.firstChild}"
                value="&lt;ul&gt;" escape="false" />
        <li>
          <h:outputText value="#{node.value}" />
        </li>
        <ui:repeat rendered="#{node.lastChild and empty node.kids}"
            value="#{node.lastChildLineage}" var="ignore">
          <h:outputText
              value="&lt;/ul&gt;" escape="false" />
        </ui:repeat>
      </ui:repeat>
    </ul>
  </h:body>
</html>
@javax.faces.bean.ManagedBean(name = "tree")
@javax.faces.bean.RequestScoped
public class Tree {
  private Node<String> root = new Node(null, "JSF Stuff");

  @PostConstruct
  public void initData() {
    root.getKids().add(new Node(root, "Chapter One"));
    root.getKids().add(new Node(root, "Chapter Two"));
    root.getKids().add(new Node(root, "Chapter Three"));
    Node<String> chapter2 = root.getKids().get(1);
    chapter2.getKids().add(new Node(chapter2, "Section A"));
    chapter2.getKids().add(new Node(chapter2, "Section B"));
  }

  public List<Node<String>> getTreeNodes() {
    return walk(new ArrayList<Node<String>>(), root);
  }

  private List<Node<String>> walk(List<Node<String>> list, Node<String> node) {
    list.add(node);
    for(Node<String> kid : node.getKids()) {
      walk(list, kid);
    }
    return list;
  }
}
public class Node<T> {
  private T value;
  private Node<T> parent;
  private LinkedList<Node<T>> kids = new LinkedList<>();

  public Node(Node<T> parent, T value) {
    this.parent = parent;
    this.value = value;
  }

  public List<Node<T>> getKids() {return kids;}
  public T getValue() { return value; }

  public boolean getHasParent() { return parent != null; }

  public boolean isFirstChild() {
    return parent != null && parent.kids.peekFirst() == this;
  }

  public boolean isLastChild() {
    return parent != null && parent.kids.peekLast() == this;
  }

  public List<Node> getLastChildLineage() {
    Node node = this;
    List<Node> lineage = new ArrayList<>();
    while(node.isLastChild()) {
        lineage.add(node);
        node = node.parent;
    }
    return lineage;
  }
}
  • Use the binding attribute to bind a control (e.g. some form of panel) to a backing bean that provides the UIComponent instance and its children - you write code to instantiate the UIComponent and add whatever children you want. See the spec for the binding attribute contract.
  • Write a custom control, implementing some of: a UIComponent; a Renderer; a tag handler; meta-data files (delete as appropriate - you do some or all of these depending on what you are doing and how and in which version of JSF).

@ McDowell: Thanks for providing example code with your answer. Building on such iterative basis seems hackyish but I also find it interesting :) Never thought of that. I feel this only works when the tree is built in right order. However, that wouldn't be a problem. @ BalusC: Thanks for pointer to the themeroller. I fear it's too simple, however. Each component also has their own CSS, which you don't customize in themeroller. However, I will take another look at that, in my first glance I didn't find how to override the component specific CSS.

@Tuukka Mustonen - the stateful component tree that underlies the JSF framework makes what you want difficult and it would be a breaking change to remove that.

Here's a model-driven approach that doesn't involve writing custom components or backing-bean-generated component trees. It's kind of ugly.

I would favour an imperative approach. You have two options as I see it:

JSF's declarative tags are ill-suited for handling this sort of recursion. JSF builds a stateful component tree that is persisted between requests. If the view is restored in a subsequent request, the view state may not reflect changes in the model.

PrimeFaces supports/uses jQuery themeroller CSS framework. The average CSS designer should already be familiar with that.

Thanks for your suggestions. I have to say I am little disappointed with JSF 2.0 if this is the case. Still looking for other viewpoints, but probably I'll have to follow this road. I've glanced at RichFaces and PrimeFaces, but they seem terribly heavyweight and their styling seems to require more work than I would like (we already have XHTML/CSS templates) so I am still looking to build a custom navigation tree.

Try your algorithm with a tree with only one child per node. The three will render everything on the same level.

Note
Rectangle 27 0

java Recursion in JSF (c:forEach vs. ui:repeat)?


<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core" >
    <ul>
        <c:forEach items="#{node.children}" var="child">
            <li>
                #{child.label}
                <ui:include src="recursive.xhtml">
                    <ui:param name="node" value="#{child}" />
                </ui:include>
            </li>
        </c:forEach>
    </ul>   
</ui:composition>
<ui:include src="recursive.xhtml">
    <ui:param name="node" value="#{child}" />
</ui:include>
xmlns:c="http://java.sun.com/jstl/core"

I had a similar issue(StackOverflowException) while migrating our app from jsf 1.x to 2.x. If you're using the c:forEach approach to jsf recursion, make sure you're using the new namespace for jstl core. Use

Just wanted to clarify, in our case, recursion is implemented using nested ui:include/c:forEach.

The question did mention StackoverflowException using c:forEach, which is what I got with the invalid namespace. I updated the answer to include the full code for the recursion.

instead of

Note
Rectangle 27 0

java Recursion in JSF (c:forEach vs. ui:repeat)?


*  JSF Stuff
      o Chapter One
      o Chapter Two
            + Section A
            + Section B 
      o Chapter Three
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head><title>Facelet Tree</title></h:head>
  <h:body>
    <ul>
      <ui:repeat value="#{tree.treeNodes}" var="node">
        <h:outputText rendered="#{node.firstChild}"
                value="&lt;ul&gt;" escape="false" />
        <li>
          <h:outputText value="#{node.value}" />
        </li>
        <ui:repeat rendered="#{node.lastChild and empty node.kids}"
            value="#{node.lastChildLineage}" var="ignore">
          <h:outputText
              value="&lt;/ul&gt;" escape="false" />
        </ui:repeat>
      </ui:repeat>
    </ul>
  </h:body>
</html>
@javax.faces.bean.ManagedBean(name = "tree")
@javax.faces.bean.RequestScoped
public class Tree {
  private Node<String> root = new Node(null, "JSF Stuff");

  @PostConstruct
  public void initData() {
    root.getKids().add(new Node(root, "Chapter One"));
    root.getKids().add(new Node(root, "Chapter Two"));
    root.getKids().add(new Node(root, "Chapter Three"));
    Node<String> chapter2 = root.getKids().get(1);
    chapter2.getKids().add(new Node(chapter2, "Section A"));
    chapter2.getKids().add(new Node(chapter2, "Section B"));
  }

  public List<Node<String>> getTreeNodes() {
    return walk(new ArrayList<Node<String>>(), root);
  }

  private List<Node<String>> walk(List<Node<String>> list, Node<String> node) {
    list.add(node);
    for(Node<String> kid : node.getKids()) {
      walk(list, kid);
    }
    return list;
  }
}
public class Node<T> {
  private T value;
  private Node<T> parent;
  private LinkedList<Node<T>> kids = new LinkedList<>();

  public Node(Node<T> parent, T value) {
    this.parent = parent;
    this.value = value;
  }

  public List<Node<T>> getKids() {return kids;}
  public T getValue() { return value; }

  public boolean getHasParent() { return parent != null; }

  public boolean isFirstChild() {
    return parent != null && parent.kids.peekFirst() == this;
  }

  public boolean isLastChild() {
    return parent != null && parent.kids.peekLast() == this;
  }

  public List<Node> getLastChildLineage() {
    Node node = this;
    List<Node> lineage = new ArrayList<>();
    while(node.isLastChild()) {
        lineage.add(node);
        node = node.parent;
    }
    return lineage;
  }
}
  • Use the binding attribute to bind a control (e.g. some form of panel) to a backing bean that provides the UIComponent instance and its children - you write code to instantiate the UIComponent and add whatever children you want. See the spec for the binding attribute contract.
  • Write a custom control, implementing some of: a UIComponent; a Renderer; a tag handler; meta-data files (delete as appropriate - you do some or all of these depending on what you are doing and how and in which version of JSF).

@ McDowell: Thanks for providing example code with your answer. Building on such iterative basis seems hackyish but I also find it interesting :) Never thought of that. I feel this only works when the tree is built in right order. However, that wouldn't be a problem. @ BalusC: Thanks for pointer to the themeroller. I fear it's too simple, however. Each component also has their own CSS, which you don't customize in themeroller. However, I will take another look at that, in my first glance I didn't find how to override the component specific CSS.

@Tuukka Mustonen - the stateful component tree that underlies the JSF framework makes what you want difficult and it would be a breaking change to remove that.

Here's a model-driven approach that doesn't involve writing custom components or backing-bean-generated component trees. It's kind of ugly.

I would favour an imperative approach. You have two options as I see it:

JSF's declarative tags are ill-suited for handling this sort of recursion. JSF builds a stateful component tree that is persisted between requests. If the view is restored in a subsequent request, the view state may not reflect changes in the model.

PrimeFaces supports/uses jQuery themeroller CSS framework. The average CSS designer should already be familiar with that.

Thanks for your suggestions. I have to say I am little disappointed with JSF 2.0 if this is the case. Still looking for other viewpoints, but probably I'll have to follow this road. I've glanced at RichFaces and PrimeFaces, but they seem terribly heavyweight and their styling seems to require more work than I would like (we already have XHTML/CSS templates) so I am still looking to build a custom navigation tree.

Try your algorithm with a tree with only one child per node. The three will render everything on the same level.

Note
Rectangle 27 0

java Recursion in JSF (c:forEach vs. ui:repeat)?


<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core" >
    <ul>
        <c:forEach items="#{node.children}" var="child">
            <li>
                #{child.label}
                <ui:include src="recursive.xhtml">
                    <ui:param name="node" value="#{child}" />
                </ui:include>
            </li>
        </c:forEach>
    </ul>   
</ui:composition>
<ui:include src="recursive.xhtml">
    <ui:param name="node" value="#{child}" />
</ui:include>
xmlns:c="http://java.sun.com/jstl/core"

I had a similar issue(StackOverflowException) while migrating our app from jsf 1.x to 2.x. If you're using the c:forEach approach to jsf recursion, make sure you're using the new namespace for jstl core. Use

Just wanted to clarify, in our case, recursion is implemented using nested ui:include/c:forEach.

The question did mention StackoverflowException using c:forEach, which is what I got with the invalid namespace. I updated the answer to include the full code for the recursion.

instead of

Note