我可以递归地嵌入复合组件吗?

时间:2011-12-09 13:53:41

标签: jsf recursion jsf-2 primefaces composite-component

我有自己的DTO(它是嵌套的)。

public class MyDTO {

   private SomeData someData;
   private MyDTO nested;

   // getters and setters
}

我创建了复合组件,它以递归方式调用自身。我称之为:

<screen:my-dto-screen dto="#{myDTOBean.myDto}" />

定义是:

  <composite:interface>
    <composite:attribute name="dto"/>
</composite:interface>
        -- display "someData" here --
    <p:panel rendered="#{cc.attrs.dto.nested != null}" /> -- this acts as recursion bottom --
       <screen:my-dto-screen dto="#{cc.attrs.dto.nested}" />            
    </p:panel>
<composite:implementation>

真正的代码并不简单,但我写这篇文章是为了让您简单了解问题所在。一切似乎都很好,但我认为有一些奇怪的例外。

javax.servlet.ServletException
javax.faces.webapp.FacesServlet.service(FacesServlet.java:422)
org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:368)
cayetano.games.common.web.security.OperatorPermissionsFilter.doFilter(OperatorPermissionsFilter.java:74)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
cayetano.games.common.web.security.WebUsernamePasswordAuthenticationFilter.actualDoFilter(WebUsernamePasswordAuthenticationFilter.java:65)
cayetano.games.common.web.security.WebUsernamePasswordAuthenticationFilter.doFilter(WebUsernamePasswordAuthenticationFilter.java:43)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

root cause

java.lang.StackOverflowError
java.util.regex.Pattern$Curly.match(Pattern.java:3754)
java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3383)
java.util.regex.Pattern$Slice.match(Pattern.java:3499)
java.util.regex.Pattern$GroupTail.match(Pattern.java:4244)
java.util.regex.Pattern$BranchConn.match(Pattern.java:4095)
java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3383)
java.util.regex.Pattern$Branch.match(Pattern.java:4131)
java.util.regex.Pattern$GroupHead.match(Pattern.java:4185)
java.util.regex.Pattern$CharProperty.match(Pattern.java:3362)
java.util.regex.Pattern$Start.match(Pattern.java:3072)
java.util.regex.Matcher.search(Matcher.java:1116)
java.util.regex.Matcher.find(Matcher.java:552)
com.sun.faces.el.ELUtils.isCompositeComponentExpr(ELUtils.java:195)
com.sun.faces.facelets.tag.TagAttributeImpl.getValueExpression(TagAttributeImpl.java:388)
com.sun.faces.facelets.tag.TagAttributeImpl.getValueExpression(TagAttributeImpl.java:351)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler$CompositeComponentRule$CompositeExpressionMetadata.applyMetadata(CompositeComponentTagHandler.java:588)
com.sun.faces.facelets.tag.MetadataImpl.applyMetadata(MetadataImpl.java:81)
javax.faces.view.facelets.MetaTagHandler.setAttributes(MetaTagHandler.java:129)
javax.faces.view.facelets.DelegatingMetaTagHandler.setAttributes(DelegatingMetaTagHandler.java:102)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.setAttributes(CompositeComponentTagHandler.java:226)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:183)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
com.sun.faces.facelets.tag.composite.ImplementationHandler.apply(ImplementationHandler.java:81)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:86)
com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:152)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyCompositeComponent(CompositeComponentTagHandler.java:349)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:190)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
com.sun.faces.facelets.tag.composite.ImplementationHandler.apply(ImplementationHandler.java:81)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:86)
com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:152)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyCompositeComponent(CompositeComponentTagHandler.java:349)
com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:190)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:98)
javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:188)
javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
com.sun.faces.facelets.tag.composite.ImplementationHandler.apply(ImplementationHandler.java:81)

2 个答案:

答案 0 :(得分:2)

在视图构建期间发生此异常。在视图构建期间,rendered属性评估。它仅在视图渲染时间期间(以及在输入和命令组件的应用请求值阶段期间进行评估,但这是一个故事)。因此,您的方法将最终进入无限递归循环,最终导致内存中的堆栈溢出。

基本上,您希望在视图构建时评估条件。所以你需要一个在视图构建期间运行的标记/属性。其中一个是JSTL <c:if>

<c:if test="#{cc.attrs.dto.nested != null}">
    <p:panel>
       <screen:my-dto-screen dto="#{cc.attrs.dto.nested}" />            
    </p:panel>
</c:if>

但是,如果#{cc.attrs.dto.nested}值由render-time属性提供,则此方法不起作用,因此递归将不起作用。仅显示顶级组件。您正在寻找一种迭代方法。考虑查看现有的JSF树组件,例如PrimeFaces'<p:tree>

答案 1 :(得分:2)

我遇到了与OP类似的问题,并设法通过foreach以及BalusC提供的以下博客文章解决了这个问题。以下所有内容均引用此来源,且全部归功于BalusC:

Recursive tree of composite components

正如BalusC所述,使用在视图构建期间运行的标记/属性很重要,例如c:if和c:foreach。但是,下面的示例代码仍然会产生stackoverflowerror

<cc:interface>
    <cc:attribute name="node" type="com.example.SomeTreeModel" />
</cc:interface>
<cc:implementation>
    <c:if test="#{not empty cc.attrs.node.children}">
        <ul>
            <c:forEach items="#{cc.attrs.node.children}" var="node">
                <li>
                    #{node.data}
                    <my:tree node="#{node}" />
                </li>
            </c:forEach>
        </ul>
    </c:if>
</cc:implementation>

结果是,当您将#{node}传递给嵌套组合时,从技术上讲,您基本上就是将#{cc.attrs.node.children [index]}传递给它。嵌套的复合物进而将其#{cc.attrs.node}解释为#{cc.attrs [cc.attrs.node.children [index]]}。但是...在嵌套复合材料的上下文中,#{cc}是指嵌套复合材料本身!因此,#{cc.attrs.node}实际上是指嵌套的复合材料自己的节点。这将导致循环永无止境。

为避免我们想要的stackoverflowerror:

  1. 引用父组件

  2. 用于立即内部评估“必需变量”并将其作为基于请求的实例变量存储在某处的组合,而不是仅在组件状态下存储ValueExpression对象。支持组件是很好的候选人。

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

    private SomeTreeModel node;

    @Override
    public void setValueExpression(String name, ValueExpression expression) {
        if ("node".equals(name)) {
            setNode((SomeTreeModel) expression.getValue(getFacesContext().getELContext()));
        }
        else {
            super.setValueExpression(name, expression);
        }
    }

    public SomeTreeModel getNode() {
        return node;
    }

    public void setNode(SomeTreeModel node) {
        this.node = node;
    }

}

和组件

<cc:interface componentType="treeComposite">
    <cc:attribute name="node" type="com.example.SomeTreeModel" />
</cc:interface>
<cc:implementation>
    <c:if test="#{not empty cc.node.children}">
        <ul>
            <c:forEach items="#{cc.node.children}" var="node" varStatus="loop">
                <li>
                    #{node.data}
                    <my:tree node="#{cc.parent.node.children[loop.index]}" />
                </li>
            </c:forEach>
        </ul>
    </c:if>
</cc:implementation>