【问题标题】:Facelet tag parameter not recognized by PrimeFaces p:ajaxPrimeFaces p:ajax 无法识别 Facelet 标记参数
【发布时间】:2012-05-28 07:55:51
【问题描述】:

我有一个简单的 Facelet 标签:

<ui:composition>
  <ui:insert />
</ui:composition>

用于避免声明多个c:set 标签。
假设我在 facelets taglib 库中注册了它,名称为 view,并像这样使用它:

<my:view bean="#{myController}">
  <p:inputText value="#{bean.value}>
    <p:ajax event="blur" process="@this" listener="#{bean.handleValueChanged}" />
  </p:inputText>
</my:view>

属性valuep:inputText完美解析,但是p:ajax抛出这个:

Target Unreachable, identifier 'bean' resolved to null
javax.el.PropertyNotFoundException: Target Unreachable, identifier 'bean' resolved to null
    at com.sun.el.parser.AstValue.getTarget(AstValue.java:153)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:237)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.primefaces.component.behavior.ajax.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxBehaviorListenerImpl.java:47)

这是一个错误还是预期的行为?

更新: 我刚刚用 f:ajax 尝试了同样的方法,它奏效了!

顺便说一句,环境如下:
Glassfish 3.1.2
PF 3.0、3.2、3.3

Update2
This 问题与RichFaces 完全相同。好像是一个 PrimeFaces 错误(我今天将在 PF 错误跟踪器上发布一个问题)。

【问题讨论】:

标签: jsf-2 primefaces facelets glassfish-3


【解决方案1】:

我的同事刚刚提供了一个补丁来解决这个问题。

AjaxBehaviorListenerImpl#processAjaxBehaviour的当前实现如下:

public void processAjaxBehavior(AjaxBehaviorEvent event) throws AbortProcessingException {
        FacesContext context = FacesContext.getCurrentInstance();
        final ELContext elContext = context.getELContext();

        try{
            listener.invoke(elContext, new Object[]{});
        } catch (MethodNotFoundException mnfe) {
            MethodExpression argListener = context.getApplication().getExpressionFactory().
                        createMethodExpression(elContext, listener.getExpressionString(), null, new Class[]{event.getClass()});

            argListener.invoke(elContext, new Object[]{event});
        }
    }

他建议这样调整:

import javax.faces.view.facelets.FaceletContext;

public void processAjaxBehavior(AjaxBehaviorEvent event) throws AbortProcessingException {
        FacesContext context = FacesContext.getCurrentInstance();
        final ELContext elContext = context.getELContext();

        try{
            listener.invoke(elContext, new Object[]{});
        } catch (MethodNotFoundException mnfe) {
            FaceletContext fc = (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
            MethodExpression argListener = context.getApplication().getExpressionFactory().
                        createMethodExpression(fc, listener.getExpressionString(), null, new Class[]{ event.getClass() });

            argListener.invoke(elContext, new Object[]{ event });
        }
    }

希望这会得到 PF 团队的批准。

【讨论】:

  • 干得好!这理论上可以解决我们在标签文件中使用&lt;p:ajax event="rowEdit"&gt;时遇到的问题。
  • @BalusC 谢谢!不过,所有的荣誉都应该归功于我的同事(我怀疑他是否有 SO 帐户)。我刚刚注意到这个问题,他解决了它:) 是否有关于&lt;p:ajax event="rowEdit/&gt; 的未解决的错误或关于 SO 的问题?只是好奇,因为没碰到过这个问题,所以想看看。
  • 不,这是为了我的工作。我们有一个标签文件,其中包含一个&lt;p:column&gt;&lt;p:rowEditor&gt; 和一个&lt;p:ajax event="rowEdit" listener="#{bean.save}"&gt;,以便&lt;my:rowEditorColumn&gt; 可以将其作为单个标签包含在数据表中。然而&lt;p:ajax&gt; 从未调用监听器方法。
  • 由于原始异常是 PropertyNotFoundException 而不是 MethodNotFoundException,如何解决这个问题?
【解决方案2】:

调整不适用于我的用例,它比单个 ui:include 更复杂。

<c:forEach items="#{items}" var="item">
            <ui:include src="#{item.uri}">
                <ui:param name="itemBean" value="#{item.bean}"/>
            </ui:include>

</c:forEach>

我认为监听器的变量映射器必须在新的 MethodExpression 内部重用

【讨论】:

  • 请在 cmets 中提及或提出其他问题。 SO 不是论坛。
  • 我不能,没有足够的声誉,提出一个新问题不是解决方案。顺便说一句,我已经为这个问题提交了一个补丁code.google.com/p/primefaces/issues/detail?id=4075(作为 nithril),它被接受并应用了
  • 对信誉限制感到抱歉。这个问题在当前的 3.5 中仍然存在,修复后你的问题消失了吗?
  • 只要操作方法采用 AjaxBehaviorEvent 类型的参数而不是 PF 事件,问题就会消失。完全解决这个问题很复杂,所以我认为这是一个可以接受的解决方法