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

Posted

技术标签:

【中文标题】JSF 复合组件支持 bean EL 表达式作为必需属性的默认值失败,方法未知【英文标题】:JSF composite component backing bean EL expression as default of required attribute failing, methods not known 【发布时间】: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?

【问题讨论】:

【参考方案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。 很有趣...我自己也要做一些测试!谢谢! :)

以上是关于JSF 复合组件支持 bean EL 表达式作为必需属性的默认值失败,方法未知的主要内容,如果未能解决你的问题,请参考以下文章

如何对 jsf 复合组件中的集合属性进行 bean 验证,约束不会触发

JSF ui:composition 和复合组件的问题

JSF 2.2 ViewScoped Bean 被多次创建

部署 JSF 复合组件以供共享使用

EL作为属性传递给数据表内的复合组件时未解析

JSF2.0 - 具有可选方法表达式的复合组件