【问题标题】:JSF composite component backing bean EL expression as default of required attribute failing, methods not knownJSF 复合组件支持 bean EL 表达式作为必需属性的默认值失败,方法未知
【发布时间】:2012-07-20 17:46:45
【问题描述】:

我有一个 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},在执行就地编辑和保存时,我会收到一个错误,即 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}" 没有正确获取 backing bean?

【问题讨论】:

    标签: jsf jsf-2 default composite-component


    【解决方案1】:

    根据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,因为它使用default属性的ValueExpression的结果,即字符串"1"

    当你指定参数时:

    <my:comp param="1" />
    

    ...它输出class java.lang.Integer,因为现在它是强制转换为为cc:attribute 指定的类型所产生的值。

    【讨论】:

    • 非常感谢。顺便说一句,我尝试了一些相关的实验,结果很奇怪,例如,如果定义一个属性 name="testInteger" type="java.lang.Integer" default="1a" (注意默认字符串中故意的字母字符)和 h :outputText value=#{cc.attrs.testInteger}" 当我调用没有显式 testInteger 的组件时,它输出 ok 为 1a (不是整数),但是如果我使用 testInteger=" 调用复合组件1b" 它按预期失败,出现 NumberFormatException。
    • 很有趣...我自己也要做一些测试!谢谢! :)
    猜你喜欢
    • 2012-10-21
    • 1970-01-01
    • 2011-07-24
    • 2014-11-07
    • 2011-07-23
    • 2017-07-18
    • 2012-06-19
    • 2013-06-29
    • 2012-10-18
    相关资源
    最近更新 更多