According to https://stackoverflow.com/a/8446728/1797006 using the JSF composite component nested:cif recursively and terminating the recursion with c:if should work:
<?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://xmlns.jcp.org/jsf/html"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:nested="http://xmlns.jcp.org/jsf/composite/nested"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<cc:interface>
<cc:attribute name="theAttr"
type="richtercloud.jsf.avoid.nested.rendered.evaluation.Entity0"
required="true"/>
</cc:interface>
<cc:implementation>
<h:outputLabel value="Hello World!"/>
<c:if test="#{cc.attrs.theAttr.reference ne null}">
<nested:cif theAttr="#{cc.attrs.theAttr.reference}"/>
</c:if>
<c:if test="#{cc.attrs.theAttr.reference eq null}">
<h:outputLabel value="recursion terminated"/>
</c:if>
</cc:implementation>
</html>
when called as follows:
<?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://xmlns.jcp.org/jsf/html"
xmlns:nested="http://xmlns.jcp.org/jsf/composite/nested">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<nested:cif theAttr="#{backingBean0.reference}"/>
</h:body>
</html>
Backing bean:
@Named
@ViewScoped
public class BackingBean0 implements Serializable {
private Entity0 reference = new Entity0(new Entity0(null));
public Entity0 getReference() {
return reference;
}
public void setReference(Entity0 reference) {
this.reference = reference;
}
}
However, I'm getting a
java.lang.StackOverflowError
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.get(HashMap.java:557)
at javax.faces.component.ComponentStateHelper.get(ComponentStateHelper.java:174)
at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2386)
at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
at javax.el.MapELResolver.getValue(MapELResolver.java:199)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.ContextualCompositeValueExpression.getValue(ContextualCompositeValueExpression.java:158)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2427)
at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
at javax.el.MapELResolver.getValue(MapELResolver.java:199)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.ContextualCompositeValueExpression.getValue(ContextualCompositeValueExpression.java:158)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2427)
at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
at javax.el.MapELResolver.getValue(MapELResolver.java:199)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.ContextualCompositeValueExpression.getValue(ContextualCompositeValueExpression.java:158)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2427)
at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
at javax.el.MapELResolver.getValue(MapELResolver.java:199)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
[a few more hundred lines]
When I place a debugger breakpoint in Entity0.getReference I see that it's invoked once before the StackOverflowError.
Afaik the only other issue covered in other SO question is using rendered to break the recursion which doesn't work because of view build time vs. view render time.
I expect the recursion to cause the "Hello world!" label to be displayed twice because of the depth of 2 which is defined by private Entity0 reference = new Entity0(new Entity0(null)); (Entity0 is a class without only one property which is a reference to itself) and then the "recursion terminated label".
An SSCCE can be found at https://gitlab.com/krichter/jsf-avoid-nested-rendered-evaluation.
I'm using Primefaces 6.2 on Payara 4.1.2.181.