Итак, со всеми этими адаптациями и исправлением для другой платформы, теперь, наконец, мой компонент работает как нужно.
рабатываю пользовательский компонент JSF. Этот компонент предназначен для инкапсуляции другого компонента (а именно таблицы PrimeFaces) и добавления к нему настраиваемого поведения. Например, одна из поддерживаемых функций - динамическое создание столбцов PrimeFaces из базовых данных или определенных атрибутов. Кроме того, он поддерживает объявление дополнительных столбцов PrimeFaces в XHTML, которые также должны быть добавлены в инкапсулированную таблицу PrimeFaces.
Рассмотрим этот пример:
<my:table id="table" fields="title,label,value,additional">
<primefaces:column id="additional">
some content
</primefaces:column>
</my:table>
Мой пользовательский компонент динамически создает столбцы PrimeFaces изfields
атрибут во время рендеринга. Затем он перемещает все свои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: 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)
Итак, толькоcolumn
который был перемещен из моей таблицы в таблицу PrimeFaces, создает эту ошибку. Другие столбцы не воссоздаются, потому что во время рендеринга я использую переменную экземпляра, хранящуюся вStateHelper
чтобы указать, что столбцы уже созданы.
Я как-то понимаю, откуда исходит это исключение и что оно имеет отношение к JSF, сохраняющему полное дерево компонентов, и когда JSF восстанавливает представление, сохраненное состояние несовместимо с XHTML. Чего я не знаю, так это как решить эту проблему.
Может кто-нибудь объяснить мне, как именно работает этот механизм сохранения состояний, особенно в сочетании с динамически добавляемыми дочерними элементами и как избежать этого исключения?
ОБНОВЛЕНИЕ (10.02.2017)Я создал небольшой пример проекта без дополнительных каркасов, которые использовались ранее. Это можно найти на моемПрофиль GitHub, Одной из основных рамок, которая использовалась ранее, было возиться сAddRemoveListeners
установлен вStateContext
для воспроизведения динамических действий. Чтобы это не повлияло на мою проблему и не создавало воспроизводимую среду, я удалил их.
Поведение, которое я наблюдаю сейчас, немного отличается (больше нет исключений) и зависит от того,частичное сохранение состояния включен / отключен, и метод, который я использую для перемещенияprimefaces:column
:
При первом рендеринге таблица во всех случаях работает нормально. Затем я выполняю запрос обратной передачи, отправляя пейджинговый запрос. В некоторых случаях поведение является ошибочным.
Частичное сохранение состояния включеноЕсли включено частичное сохранение состояния, подкачка не работает. Я не получаю исключения, но много предупреждений, подобных этому:
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
Это предупреждение появляется для каждого компонента, который был динамически создан или перемещен вprimefaces:table
или был дочерним компонентом одного из них.
Если частичное сохранение состояния отключено, подкачка работает, но показывает другое поведение в зависимости от того, когда пользовательскийprimefaces:column
перемещен
Когдаprimefaces:column
перемещается во время фазы ответа рендеринга, например вencodeXxx
все работает нормально. Все столбцы в правильном порядке и с правильными значениями и подкачки прекрасно работает.
При использовании этого подхода согласно@BalusC предложение, переехалprimefaces:column
исчезает при поискеPostAddToViewEvent
вызывается несколько раз иcolumn
перемещается при обработке этого события, однако при рендеринге оно исчезает и создаются только три ранее созданных события.column
с еще там.
На данный момент, я более чем смущен. Это ошибка в Мохарре или в Primefaces, или я делаю что-то не так? Возможно ли такое поведение даже с JSF?