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.