JSF 状态保存和自定义组件与动态添加的子项 [英] JSF State saving and custom components with dynamically added children

查看:16
本文介绍了JSF 状态保存和自定义组件与动态添加的子项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 JSF 自定义组件.该组件的目的是封装另一个组件(即 PrimeFaces 表)并向其添加自定义行为.例如,它支持的功能之一是从基础数据或某些属性动态创建 PrimeFaces 列.此外,它还支持在 XHTML 中声明额外的 PrimeFaces 列,这些列也应该添加到封装的 PrimeFaces 表中.

考虑这个例子:

<primefaces:column id="additional">一些内容</primefaces:column></my:table>

我的自定义组件在渲染期间根据 fields 属性动态创建 PrimeFaces 列.然后将其所有 column 子项移动到 PrimeFaces 表,因此在渲染组件树后如下所示:

my:table id="table"|---primefaces:table id="table_table"|---primefaces:column id="title"|---primefaces:column id="label"|---primefaces:column id="value"|---primefaces:column id="additional"

在第一次渲染期间,这工作正常.但是,当我对组件执行 AJAX 更新时,出现以下异常:

javax.faces.FacesException: 不能两次删除同一个组件:table:additional在 com.sun.faces.context.StateContext$DynamicAddRemoveListener.handleAddRemoveWithAutoPrune(StateContext.java:761)在 com.sun.faces.context.StateContext$DynamicAddRemoveListener.handleRemove(StateContext.java:629)在 com.sun.faces.context.StateContext$AddRemoveListener.processEvent(StateContext.java:342)在 com.sun.faces.context.StateContext$DynamicAddRemoveListener.processEvent(StateContext.java:565)在 javax.faces.event.SystemEvent.processListener(SystemEvent.java:108)在 javax.faces.event.ComponentSystemEvent.processListener(ComponentSystemEvent.java:118)在 com.sun.faces.application.ApplicationImpl.processListenersAccountingForAdds(ApplicationImpl.java:2218)在 com.sun.faces.application.ApplicationImpl.invokeViewListenersFor(ApplicationImpl.java:2036)在 com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:290)在 com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:245)在 javax.faces.application.ApplicationWrapper.publishEvent(ApplicationWrapper.java:726)在 javax.faces.component.UIComponentBase.disconnectFromView(UIComponentBase.java:2275)在 javax.faces.component.UIComponentBase.doPreRemoveProcessing(UIComponentBase.java:1939)在 javax.faces.component.UIComponentBase.setParent(UIComponentBase.java:437)在 javax.faces.component.UIComponentBase$ChildrenList.remove(UIComponentBase.java:2757)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.adjustIndexOfDynamicChildren(ComponentTagHandlerDelegateImpl.java:283)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:223)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 com.sun.faces.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:106)在 com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:206)在 com.sun.faces.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:395)在 com.sun.faces.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:366)在 com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:111)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:194)在 com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)在 com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)在 com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)在 com.sun.faces.facelets.tag.ui.IncludeHandler.apply(IncludeHandler.java:124)在 com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:116)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 com.sun.faces.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:106)在 com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:206)在 com.sun.faces.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:395)在 com.sun.faces.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:366)在 com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:111)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 com.sun.faces.facelets.tag.jsf.core.ViewHandler.apply(ViewHandler.java:225)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)在 com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)在 com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)在 com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)在 com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:174)在 com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)在 com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)在 com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)在 com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)在 com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:174)在 com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)在 com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)在 com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161)在 com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:1006)在 com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99)在 com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)在 com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)在 javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)在 de.gebit.trend.servlet.security.AuthorizationFilter.doFilter(AuthorizationFilter.java:269)在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)在 org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)在 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)在 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)在 java.util.concurrent.ThreadPoolExecutor.runWorker(未知来源)在 java.util.concurrent.ThreadPoolExecutor$Worker.run(未知来源)在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)在 java.lang.Thread.run(未知来源)

因此,只有从我的表移动到 PrimeFaces 表的 column 会产生此错误.其他列不会重新创建,因为在渲染期间,我使用存储在 StateHelper 中的实例变量来指示列已经创建.

我以某种方式理解这个异常是从哪里来的,它与 JSF 保存完整组件树有关,并且当 JSF 恢复视图时,保存的状态与 XHTML 不一致.我不知道的是,如何解决这个问题.

有人可以向我解释这种状态保存机制究竟是如何工作的,尤其是在与动态添加的子项结合使用时,以及如何避免这种异常?

更新 (10.02.2017)

我创建了一个小型示例项目,没有使用之前使用的其他框架.它可以在我的 GitHub 个人资料 上找到.以前使用的一个主要框架是摆弄安装在 StateContext 中的 AddRemoveListeners,用于重放动态操作.为了避免这对我的问题产生影响并创建一个可重现的环境,我删除了它们.

我现在看到的行为略有不同(不再有例外),取决于是否启用/禁用部分状态保存以及我用来移动 primefaces:column 的方法:

表格的第一次渲染在所有情况下都能正常工作.然后我通过提交分页请求来执行回发请求.在某些情况下,这种行为是错误的.

启用部分状态保存

启用部分状态保存后,分页不起作用.我没有得到异常,但有很多类似的警告:

2017 年 2 月 10 日下午 4:33:11 com.sun.faces.application.view.FaceletPartialStateManagementStrategy saveDynamicActions警告:无法使用 clientId 'form:table:table_table:additional' 保存动态操作,因为找不到 UIComponent

对于在 primefaces:table 中动态创建或移动到其中或作为其中之一的子组件的每个组件,都会出现此警告.

部分状态保存已禁用

禁用部分状态保存后,分页确实可以工作,但会根据移动自定义 primefaces:column 的时间显示不同的行为.

在渲染响应阶段移动`column`

primefaces:column 在渲染响应阶段移动时,例如在 encodeXxx 中,一切正常.所有列的顺序都正确,值正确,分页工作正常.

使用 `PostAddToViewEvent` 移动 `column`

当使用这种方法时,根据 @BalusC 的建议,移动的 primefaces:column 在分页时消失.PostAddToViewEvent 被多次调用,并且 column 在处理这个事件时被移动,但是在渲染时,它消失了,只有之前创建的三个 column>s 还在那里.

在这一点上,我非常困惑.这是 Mojarra 或 Primefaces 中的错误还是我做错了什么?JSF 甚至可以实现这种行为吗?

解决方案

简单的答案是:正在使用的其他框架故障.该框架覆盖了 JSF 的状态保存机制,并用自定义机制替换了它.然而,实现是错误的,并且没有照顾负责正确保存动态组件操作的 DynamicAddRemoveListeners.他们修复了错误,现在可以正常工作了.

但是,我想指出以下几点是修复组件所必需的:

首先@BalusC 向我指出了在自定义 JSF 组件中移动子组件的正确方法:应该使用 PostAddToView 事件监听器.

<块引用>

@ListenerFor(systemEventClass=PostAddToViewEvent.class)公共类 YourComponent 扩展了 SomeUIComponent {@覆盖公共无效过程事件(组件系统事件事件){如果(事件实例 PostAddToViewEvent){targetParent.getChildren().add(componentToMove);}}}

然而,这种方法有一个缺点,即此时不会设置组件属性.因此,如果您需要这些,则只能在渲染响应阶段创建/移动组件.

第二,自定义JSF组件的子组件不应该保存在StateHelper中.应该在每次请求时重新创建它们,以便 JSF 在重放动态动作时找到这些组件.

第三,动态创建的子组件的ID(如果设置)应该在组件自身创建时设置.我的自定义组件仅在渲染响应阶段设置其子组件的 ID,因此当 JSF 尝试重放动态操作时,它找不到相应的组件.这是上述启用部分状态保存部分中提到的问题的解决方案.

因此,通过所有这些调整和对其他框架的修复,现在我的组件终于可以正常工作了.

I am developing a JSF custom component. This component has the purpose of encapsulating another component (namely a PrimeFaces table) and adding customized behaviour to it. For example, one of the features that it supports is creating PrimeFaces columns dynamically from the underlying data or from certain attributes. Furthermore, it supports declaring additional PrimeFaces columns in XHTML, which should be added to the encapsulated PrimeFaces table as well.

Consider this example:

<my:table id="table" fields="title,label,value,additional">
    <primefaces:column id="additional">
        some content
    </primefaces:column>
</my:table>

My custom component dynamically creates the PrimeFaces columns from the fields attribute during rendering. It then moves all its column children to the PrimeFaces table, so after rendering the component tree looks like follows:

my:table id="table"
|---primefaces:table id="table_table"
    |---primefaces:column id="title"
    |---primefaces:column id="label"
    |---primefaces:column id="value"
    |---primefaces:column id="additional"

During first rendering, this works fine. However, when I then perform an AJAX update of my component, I get the following exception:

javax.faces.FacesException: Cannot remove the same component twice: table:additional
    at com.sun.faces.context.StateContext$DynamicAddRemoveListener.handleAddRemoveWithAutoPrune(StateContext.java:761)
    at com.sun.faces.context.StateContext$DynamicAddRemoveListener.handleRemove(StateContext.java:629)
    at com.sun.faces.context.StateContext$AddRemoveListener.processEvent(StateContext.java:342)
    at com.sun.faces.context.StateContext$DynamicAddRemoveListener.processEvent(StateContext.java:565)
    at javax.faces.event.SystemEvent.processListener(SystemEvent.java:108)
    at javax.faces.event.ComponentSystemEvent.processListener(ComponentSystemEvent.java:118)
    at com.sun.faces.application.ApplicationImpl.processListenersAccountingForAdds(ApplicationImpl.java:2218)
    at com.sun.faces.application.ApplicationImpl.invokeViewListenersFor(ApplicationImpl.java:2036)
    at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:290)
    at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:245)
    at javax.faces.application.ApplicationWrapper.publishEvent(ApplicationWrapper.java:726)
    at javax.faces.component.UIComponentBase.disconnectFromView(UIComponentBase.java:2275)
    at javax.faces.component.UIComponentBase.doPreRemoveProcessing(UIComponentBase.java:1939)
    at javax.faces.component.UIComponentBase.setParent(UIComponentBase.java:437)
    at javax.faces.component.UIComponentBase$ChildrenList.remove(UIComponentBase.java:2757)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.adjustIndexOfDynamicChildren(ComponentTagHandlerDelegateImpl.java:283)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:223)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at com.sun.faces.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:106)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:206)
    at com.sun.faces.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:395)
    at com.sun.faces.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:366)
    at com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:111)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:194)
    at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
    at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)
    at com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)
    at com.sun.faces.facelets.tag.ui.IncludeHandler.apply(IncludeHandler.java:124)
    at com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:116)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at com.sun.faces.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:106)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:206)
    at com.sun.faces.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:395)
    at com.sun.faces.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:366)
    at com.sun.faces.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:111)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at com.sun.faces.facelets.tag.jsf.core.ViewHandler.apply(ViewHandler.java:225)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:202)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
    at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
    at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)
    at com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:174)
    at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
    at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:312)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:371)
    at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:350)
    at com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:174)
    at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
    at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
    at com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:1006)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at de.gebit.trend.servlet.security.AuthorizationFilter.doFilter(AuthorizationFilter.java:269)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

So, only the column that was moved from my table to the PrimeFaces table is creating this error. The other columns do not get recreated, because during rendering, I use an instance variable stored in the StateHelper to indicate that columns are already created.

I somehow understand where this exception is coming from and that it has something to do with JSF saving the complete component tree, and when JSF restores the view, the saved state is inconsistent with the XHTML. What I don't know is, how to solve this problem.

Could someone please explain to me how this state saving mechanism exactly works, especially in conjunction with dynamically added children and how to avoid this exception?

UPDATE (10.02.2017)

I've created a small sample project without additional frameworks that were in use before. It can be found on my GitHub profile. One main framework that was in use before was fiddeling with the AddRemoveListeners installed in the StateContext for replaying dynamic actions. To avoid this having an impact on my issue and to create a reproducible environment, I removed them.

The behavior I witness now is slightly different (there are no exceptions anymore) and depends on whether partial state saving is enabled/disabled and the method I use to move the primefaces:column:

The first rendering of the table in all cases works fine. I then perform a postback request by submitting a paging request. The behavior then is erronous in some cases.

Partial state saving enabled

With partial state saving enabled, paging does not work. I do not get an exception, but a lot of warnings similar to this:

Feb 10, 2017 4:33:11 PM com.sun.faces.application.view.FaceletPartialStateManagementStrategy saveDynamicActions
WARNUNG: Unable to save dynamic action with clientId 'form:table:table_table:additional' because the UIComponent cannot be found

This warning appears for every component that was moved dynamically created in or moved to the primefaces:table or was a child component of one of those.

Partial state saving disabled

With partial state saving disabled, paging does work but shows different behavior depending on when the one custom primefaces:column is moved.

Moving of `column` during render response phase

When the primefaces:column is moved during render response phase, e.g. in encodeXxx, everything works fine. All the columns are in the correct order and with correct values and paging works perfectly fine.

Moving of `column` using a `PostAddToViewEvent`

When using this approach, as per @BalusC suggestion, the moved primefaces:column disappears on paging. The PostAddToViewEvent is called several times and the column is moved while handling this event, however on rendering, it has disappeared and only the three previously created columns are still there.

At this point, I am more than confused. Is this a bug in Mojarra or in Primefaces or am I doing something wrong? Is this kind of behavior even possible with JSF?

解决方案

The simple answer is: it is the other frameworks fault that is in use. This framework overwrites the state saving mechanism of JSF and replaces it with a custom mechanism. The implementation, however, was faulty and did not take care of the DynamicAddRemoveListeners responsible for saving the actions of dynamic componants correctly. They fixed the bug, now it works fine.

However, there were several things that were necessary to fix my component that I want to point out:

First, @BalusC pointed me to the correct way of moving child components in a custom JSF component: it should be done using a PostAddToView event listener.

@ListenerFor(systemEventClass=PostAddToViewEvent.class)
public class YourComponent extends SomeUIComponent {

     @Override
     public void processEvent(ComponentSystemEvent event) {
          if (event instanceof PostAddToViewEvent) {
              targetParent.getChildren().add(componentToMove);
          }
     }
}

This approach has the drawback, however, that the components attributes won't be set at this point. So if you need those, components can only be created/moved during render response phase.

Second, child components of a custom JSF component should not be saved in the StateHelper. They should be recreated on every request so that JSF finds these components when replaying the dynamic actions.

Third, the ID of dynamically created child components (if set) should always be set when the component is created itself. My custom component set the ID of its children components only during render response phase, so when JSF tried to replay the dynamic actions, it could not find the respective components. This was the solution to the problem mentioned above in the section Partial state saving enabled.

So with all these adaptions and the fix for the other framework, now finally my component works as desired.

这篇关于JSF 状态保存和自定义组件与动态添加的子项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆