JSF复合组件支持bean EL表达式默认为必需属性失败,方法未知

时间:2012-07-21 22:55:14

标签: jsf jsf-2 default composite-component

我有一个JSF复合组件util_primefaces:inplace_name,它需要一个“管理器”支持bean,当编辑实体的“名称”字段时(使用p:inplace)执行持久性更新:

<cc:interface>
  <cc:attribute name="manager" type="com.example.web.AbstractManager" required="false" default="#{blockManager}"/>
  <cc:attribute name="element" type="com.example.entity.Element" required="true"/>
  <cc:attribute name="elid" required="true"/>
  <cc:attribute name="update" required="false" default="@parent"/>
 ..
</cc:interface>

<cc:implementation>
 ..
 <p:inplace id="#{cc.attrs.elid}" editor="true" emptyLabel="UNDEF" >
  <p:ajax 
   event="save" 
   listener="#{cc.attrs.manager.onInplaceNameSaveEvent}"
   process="@this #{cc.attrs.elid}-name"
   update="#{cc.attrs.update}"
  />
 <h:inputText id="#{cc.attrs.elid}-name" value="#{cc.attrs.element.name}"/>
 ..

例如@ViewScoped @ManagedBean BlockManager最终扩展了一个AbstractManager,它有一个监听器方法:

public void onInplaceNameSaveEvent(AjaxBehaviorEvent ae).

[ASIDE:此处描述了不同寻常的“elid”属性的原因,它在此问题中不再发挥作用:Primefaces p:inplace: How to more elegantly propagate the EL expression for entity to merge]

当我调用复合组件传入一个显式的#{blockManager}(或AbstractManager的其他子类)时,它工作正常:

<util_primefaces:inplace_name 
 element="#{tenancy}" 
 elid="tenancy"
 manager="#{blockManager}"
/>

但是如果我没有传入#{blockManager},那么在执行inplace编辑和保存时,我得到一个错误,即onInplaceNameSaveEvent(AjaxBehaviorEvent)方法未知:

<util_primefaces:inplace_name 
 element="#{tenancy}" 
 elid="tenancy"
/>

错误是:

WARNING: Method not found: com.example.web.BlockManager@71396a88.onInplaceNameSaveEvent(javax.faces.event.AjaxBehaviorEvent)
javax.el.MethodNotFoundException: Method not found: com.example.web.BlockManager@71396a88.onInplaceNameSaveEvent(javax.faces.event.AjaxBehaviorEvent)
at com.sun.el.util.ReflectionUtil.getMethod(ReflectionUtil.java:155) 

问:为什么在复合组件属性中使用default =“#{blockManager}”未正确使用辅助bean?

1 个答案:

答案 0 :(得分:5)

根据the documentation for the tag cc:attributedefault的值必须评估为java.lang.String

这就是#{blockManager}表达式无法正常工作的原因,您只能设置String属性的默认值。

要查看会发生什么,您可以测试在taglib(like showed here)中注册以下函数:

public static String typeOf(Object o) {
    return o == null ? null : o.getClass().toString();
}

并在像这样的复合组件中使用它:

<ui:composition>
    <cc:interface>
        <cc:attribute name="param" type="java.lang.Integer" required="true"
            default="1" />
    </cc:interface>
    <cc:implementation>
        <h:outputText value="#{fnc:typeOf(cc.attrs.param)}" />
    </cc:implementation>
</ui:composition>

现在,如果您在未指定param的情况下使用该组件,请执行以下操作:

<my:comp />

...它将输出class java.lang.String,因为它使用ValueExpression的结果作为默认属性,即字符串"1"

当你指定param时:

<my:comp param="1" />

...它会输出class java.lang.Integer,因为现在它是强制转换为cc:attribute指定类型的结果。