使用 ui:repeat 的复合组件调用方法中缺少参数值

Missing parameter values in invoked method with composite components using ui:repeat

所以经过几天的调试,我们最终能够在 JSF 中重现一些我们不理解的复合组件、ui:repeatp:remoteCommand 和部分状态保存之间的奇怪交互。

场景

复合组件使用 ui:repeat 遍历对象列表。在每次迭代期间,包含另一个复合组件并传递参数。

<ui:composition (...)>
  <ui:repeat var="myVar" value="#{cc.attrs.controller.someList}">
    <namespace:myRemoteCommand someParam="SomeParam"/>

在包含的复合组件中,有一个自动 运行 p:remoteCommand 使用组件接口中定义的参数调用方法。

<ui:component (...)>
  <p:remoteCommand actionListener="#{someBean.someMethod(cc.attrs.someParam)}"
                   autoRun="true"
                   async="true"
                   global="false">

但是,在someMethod(...)中设置断点时,会传递一个空字符串。这仅在 部分状态保存 设置为 false 时发生。

解决方案

我们尝试了几种解决方案,以下似乎有效(但我们不明白原因,也无法预见可能发生的任何进一步问题):

问题

为什么 JSF 会这样?复合组件 ui:repeat 和参数传递之间的这种交互是什么,它根据我们是否使用 ui:include / 部分状态保存而改变?

我们正在使用 Primefaces 5.3、Glassfish 4.1、Mojarra 2.2.12、Java 8.

你的代码没问题。只是Mojarra的<ui:repeat>坏了。您不是第一个面临 <ui:repeat>.

状态管理相关问题的人
  • Checkbox inside ui:repeat not refreshed by Ajax
  • Dynamically added input field in ui:repeat is not processed during form submit
  • Components are with the same id inside ui:repeat
  • <h:form> within <ui:repeat> not entirely working, only the last <h:form> is processed
  • Composite component with custom backing component breaks strangely when nested inside ui:repeat
  • ui:repeat in o:tree not working as expected

你的问题的根本原因是 #{cc}<ui:repeat> 需要访问树的那一刻不可用。实际上,<ui:repeat value>null。一个快速的解决方法是使用 pushComponentToEL(facesContext, null).

显式地推送 UIRepeat#visitTree() method. Given Mojarra 2.2.12, add below lines right before line 734 中的 #{cc}
UIComponent compositeParent = getCompositeComponentParent(this);
if (compositeParent != null) {
    compositeParent.pushComponentToEL(facesContext, null);
}

并在 line 767 之后添加下面几行 popComponentFromEL(facesContext)

if (compositeParent != null) {
    compositeParent.popComponentFromEL(facesContext);
}

如果您不是从源代码构建 Mojarra,请复制整个 source code of UIRepeat into your project, maintaining its package structure and apply above changes on it. Classes in /WEB-INF/classes have higher classloading precedence than those in /WEB-INF/lib and server's /lib. I have at least created issue 4162 来解决这个问题。

另一种方法是将 Mojarra 替换为 MyFaces,或者将 <ui:repeat> 替换为具有状态管理权限的基于 UIData 的组件,例如 <h:dataTable><p:dataList> .

<p:dataList type="none" var="myVar" value="#{cc.attrs.controller.someList}">
    <namespace:myRemoteCommand someParam="SomeParam" />
</p:dataList>

您可能只想应用一些 CSS 来摆脱小部件样式(边框等),但那是 trivial

另请参阅:

  • Should PARTIAL_STATE_SAVING be set to false?