2015-05-01 17 views
8

Das Problem

Wenn ich in sich selbst zu nisten ein Composite Component versuchen, mit einem gewissen Logik, die unendliche Rekursion zu beenden erhalte ich einen Stapelüberlauf Ausnahme. Mein Verständnis ist, dass <c:xxx> tags run at view build time, so dass ich nicht erwartet hatte, eine unendliche Ansicht zu bauen, wie ich vermutete, war der Fall.Nested JSF Composite Components führt zu einem Stack-Überlauf Ausnahme

Dies ist das Verbundbauteil simpleNestable.xhtml

<!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:composite="http://java.sun.com/jsf/composite" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:em="http://xmlns.jcp.org/jsf/composite/emcomp" 

    xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"> 

    <h:head> 
     <title>This content will not be displayed</title> 
    </h:head> 
    <h:body> 
     <composite:interface> 
      <composite:attribute name="depth" required="true" type="java.lang.Integer"/> 
     </composite:interface> 

     <composite:implementation> 
      <c:if test="#{cc.attrs.depth lt 3}"> 
       #{cc.attrs.depth} 
       #{cc.attrs.depth+1} 
       <em:simpleNestable depth="#{cc.attrs.depth+1}" /> 

      </c:if> 

     </composite:implementation> 
    </h:body> 
</html> 

Dies ist, wie es

<h:head> 
    <title>Facelet Title</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    <h:outputStylesheet name="./css/default.css"/> 
    <h:outputStylesheet name="./css/cssLayout.css"/> 
</h:head> 
<h:body>   
    <emcomp:simpleNestable depth="1"/> 

</h:body> 

verwendet wird 210

Der Stapelüberlaufausnahme

java.lang.StackOverflowError 
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109) 
    at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2407) 
    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.parser.AstPlus.getValue(AstPlus.java:60) 
    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:2407) 
    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.parser.AstPlus.getValue(AstPlus.java:60) 

Die Frage

Wie kann ich Nest Verbundkomponenten (oder ähnlich) in sich (zu einem nicht vordefinierten Tiefe) ohne einen Stapelüberlauf Ausnahme Empfang

Warum ich will das

Ich habe willkürlich Daten verschachtelt, die ich in einem verschachtelten reduzierbarenSubTable von RichFaces darstellen möchte, Alternativen zu meinem Ansatz sind sehr willkommen

+0

@BalusC Ich verstehe nicht, wie ist das kein Java-ee Problem? Ist das nicht ein Teil von Java-ee? –

+0

Es ist JSF-spezifisch. Dieses Q ist für Java EE-Benutzer, die JSF nicht verwenden, nicht interessant. – BalusC

Antwort

6

Das Problem war im Zusammenhang mit der #{cc} und die Eigenheit des Composite-Attributs. Die #{cc} in einem beliebigen Attribut der verschachtelten zusammengesetzten Referenzen selbst anstelle der übergeordneten. Das Attribut, das zustandsbehaftet ist, bedeutet, dass #{cc} in jedem Kind neu bewertet wurde, das wiederum statt des Elternteils selbst referenziert. Daher der Stapelüberlauf. Es bewertet die Tiefe von sich selbst in einer Endlosschleife.

ausgetrickst ich die Statusbehaftung des Attributs durch sie staatenlos eine Trägerkomponente verwendet, wie, unter dem sie sofort auswertet machen und weist sie als Bestandteil Eigenschaft:

@FacesComponent("treeComposite") 
public class TreeComposite extends UINamingContainer { 

    private Integer depth; 

    @Override 
    public void setValueExpression(String name, ValueExpression binding) { 
     if ("depth".equals(name)) { 
      setDepth((Integer) binding.getValue(getFacesContext().getELContext())); 
     } 
     else { 
      super.setValueExpression(name, binding); 
     } 
    } 

    public Integer getDepth() { 
     return depth; 
    } 

    public void setDepth(Integer depth) { 
     this.depth = depth; 
    } 

} 

Welche in-Schnittstelle des componentType wie unten erklärt werden soll, :

<cc:interface componentType="treeComposite"> 
    <cc:attribute name="depth" type="java.lang.Integer" /> 
</cc:interface> 

und Sie, bei der Umsetzung sollte im Testreferenz denjenigen des Mutter der stateless Eigenschaft und in der verschachtelten Verbund Referenz (weil #{cc} im Attribute die verschachtelte Verbund verweist auf die verschachtelte Verbund selbst):

<cc:implementation> 
    <br />We're at depth #{cc.depth}. 
    <c:if test="#{cc.depth gt 0}"> 
     <my:tree depth="#{cc.parent.depth - 1}" /> 
    </c:if> 
</cc:implementation> 

ich nur die Bedeutung von „Tiefen“ geändert hier umgekehrt zu sein, so dass es auf nur deklarative vom Client ist, ohne dass es in dem zu bearbeitende Implementierung.Also, in dem Client müssen Sie depth="#{3}" sagen, wenn Sie 3 verschachtelt Kinder wollen:

<my:tree depth="#{3}" /> 

Beachten Sie die Bedeutung der es sich um eine EL-Ausdruck eher als eine wörtliche sein. Sonst wird setValueExpression() in der Backing-Komponente nicht aufgerufen.

+0

Damit behauptet es, dass "die folgenden Attribute erforderlich sind, aber keine Werte für sie angegeben wurden: Tiefe." Könnte ich Ihre gesamte sehen, um zu sehen, wie Sie die Attributtiefe definieren? –

+0

Auch nur zu überprüfen: sind Ihre 'cc' und' meine': 'xmlns: cc =" http: // xmlns.jcp.org/jsf/composite "und' xmlns: my = "http://xmlns.jcp .org/jsf/composite/emcomp' –

+0

Schnittstelle hat genau das Tiefenattribut wie Sie hatten. Die Namespaces sind in der Tat so. Ich kanonisierte sie einfach (um zu verhindern, dass zukünftige Leser das gleiche Problem haben, wenn sie denken, dass es der "befürwortete" Stil ist. "Aber BalusC hat es so benutzt!" Usw.: /). – BalusC