PrimeFaces 12复合属性传方法时SelectEvent为null的原因与解决
问题描述
使用PrimeFaces 12 + Jakarta EE 10开发时,将方法作为复合组件属性传递,出现传入的SelectEvent为null的问题:
- 复合组件
<compositeremittance:RemittanceOutSettlementBanks>的接口定义:
<composite:interface> <composite:attribute name="selectReceiverBank" method-signature="void selectReceiverBank(org.primefaces.event.SelectEvent)" /> </composite:interface>
- 复合组件内部将该属性作为
<p:ajax>的dialogReturn事件监听器:
<p:commandButton id="receiverBankSearch" class="iscSelectCommand" icon="fa fa-search" actionListener="#{queryBuilder.showDialog()}" immediate="true" process="@this" partialSubmit="true" disabled="${not ModeOperator}"> <f:param name="queryId" value="2"/> <p:ajax event="dialogReturn" listener="#{cc.attrs.selectReceiverBank}" update="receiverBankPanel" process="receiverBankPanel" /> </p:commandButton>
- 后端基类中的方法定义:
public void selectReceiverBank(SelectEvent event) { Banks selectedBank = (Banks) event.getObject(); if (selectedBank != null) { this.remittance.setReceiverBankId(selectedBank.getBankId()); } }
问题现象:通过复合组件属性调用selectReceiverBank时,event参数为null;但直接将监听器绑定为#{myBean.selectReceiverBank}时,SelectEvent能正常传递。
原因与解决方案
原因
直接在<p:ajax>中使用listener="#{cc.attrs.selectReceiverBank}"时,JSF不会自动将dialogReturn事件生成的SelectEvent对象注入到方法参数中。复合组件的方法属性本质是一个方法表达式,若不明确指定参数传递,JSF会尝试调用无参版本的方法,导致有参方法接收的参数为null。而直接绑定#{myBean.selectReceiverBank}时,PrimeFaces的ajax机制会自动识别方法签名并传递事件参数。
解决方案
有两种可行的解决方式:
方式一:EL表达式中明确传递事件参数
修改复合组件内部的<p:ajax>标签,在监听器调用时直接传递event参数:
<p:ajax event="dialogReturn" listener="#{cc.attrs.selectReceiverBank(event)}" update="receiverBankPanel" process="receiverBankPanel" />
复合组件接口的method-signature保持原有定义即可,EL表达式会将dialogReturn事件产生的SelectEvent对象作为参数传递给目标方法。
方式二:通过复合组件后台类包装调用
- 创建复合组件对应的后台类,继承
UINamingContainer:
@FacesComponent("RemittanceOutSettlementBanks") public class RemittanceOutSettlementBanksComponent extends UINamingContainer { public void handleReceiverBankSelection(SelectEvent event) { // 获取复合组件属性中的方法表达式 MethodExpression selectMethod = (MethodExpression) getAttributes().get("selectReceiverBank"); // 调用方法并传递事件参数 selectMethod.invoke(getFacesContext().getELContext(), new Object[]{event}); } }
- 修改复合组件接口,指定后台类(若组件名和类名匹配可省略此步):
<composite:interface componentType="RemittanceOutSettlementBanks"> <composite:attribute name="selectReceiverBank" method-signature="void selectReceiverBank(org.primefaces.event.SelectEvent)" /> </composite:interface>
- 修改复合组件内部的
<p:ajax>监听器,绑定到后台类的包装方法:
<p:ajax event="dialogReturn" listener="#{cc.handleReceiverBankSelection}" update="receiverBankPanel" process="receiverBankPanel" />
内容的提问来源于stack exchange,提问作者Ali Kheiri
相关产品推荐
相关产品推荐

