【问题标题】:Programmatically instantiating ValueExpressions以编程方式实例化 ValueExpressions
【发布时间】:2013-08-11 06:23:14
【问题描述】:

我在PreRenderViewEvent上动态添加组件,使用下面的方法http://blog.kennardconsulting.com/2010/10/safely-manipulating-component-tree-with.html

对于组件添加部分效果很好,但是当我尝试动态实例化 ValueExpression-s 时出现问题。

更具体地说,当我尝试使用动态传递的参数伪造动态 ValueExpression 时遇到问题。

让我们试着解释一个例子......

在顶层,我使用了一个标签组件(标签文件中描述的组件,not 是复合组件,not 是自定义组件。

<my:topComponent param=#{toto}"/>

在 my:topComponent 中,我将参数传递给嵌套组件。

<my:nestedComponent param2=#{param}/>

这个nestedComponent 正在使用一个自定义组件(在我的例子中,是我从primefaces Datatable 派生的一个组件),将它作为另一个参数传递param2...

<my:customComponent finalParam=#{param2}/>

在customComponent中,我在PreRenderViewEvent上动态添加了一些子组件,并为customComponent设置了一些ValueExpression-s。

其中一些表达式使用 finalParam。所以,我解开 finalParam 值,然后构建一个新的 ValueExpression :

String varName = getValueExpression("finalParam").getExpressionString().replace("#{", "").replace("}", "");

然后我使用这个辅助函数实例化我的动态值表达式:

public static ValueExpression createValueExpression(String expression, Class clazz) {
        FacesContext fc = FacesContext.getCurrentInstance();
        ELContext elContext = fc.getELContext();
        ExpressionFactory expFactory = fc.getApplication().getExpressionFactory();
        ValueExpression ret = expFactory.createValueExpression(elContext, expression, clazz);
        return ret;
    }

例子:

ValueExpression dynExpression = JSFUtils.createValueExpression("#{" + varName + ".code" + "}"), Object.class);

在本例中,值表达式为“#{param2.code}”

然后我可以将此 valueExpression 设置为我的组件:

this.setValueExpression("rowKey", dynExpression);

所有这些代码都在自定义组件类中。我使用基类的渲染器。

但是,以编程方式实例化的 ValueExpression 在呈现期间未正确评估。例如,当 primefaces 数据表渲染器尝试计算 rowKey 时,#{param2.code} 被评估为“null”,因为 param2 似乎是未知的。

我应该怎么做才能纠正这个问题?在调试时,我注意到 getValueExpression("finalParam") 有一个 VariableMapper 集,而 dynExpression 没有(空值)

如果我猜对了,这个 VariableMapper 用于将 param2 转换为 param。

如何实例化我的动态表达式以保留 VariableMapper(s) 链? FunctionMapper 的问题也是一样的。

提前致谢。

更新 我同意 Richard Kennard 的回复:这似乎是同一个错误。

由于我等不及多年的修复,我使用以下组件递归解析变量。它适用于我的 MyFaces 2.1.9 / CODI 1.0.5 / OWB 1.1.6 / Tomcat 7 堆栈的简单案例。

    public static String getValueExpressionExpression(ValueExpression valueExpression) {
        return valueExpression.getExpressionString().replace("#{", "").replace("}", "");
    }

    public static String getMappedValueExpression(ValueExpression valueExpression) {
        ContextAwareTagValueExpression ctxAware = (ContextAwareTagValueExpression)valueExpression;
        if(ctxAware != null) {
            return getMappedValueExpression((WrappedValueExpression)ctxAware.getWrapped());
        }
        return getValueExpressionExpression(valueExpression);
    }

    public static String getMappedValueExpression(WrappedValueExpression wrappedExpression) {
        String exprString = wrappedExpression.getExpressionString().replace("#{", "").replace("}", "");
        String ret = exprString;
        try {

            Field valueExpression = WrappedValueExpression.class.getDeclaredField("valueExpression");
            valueExpression.setAccessible(true);
            ValueExpressionImpl vei = (ValueExpressionImpl) valueExpression.get(wrappedExpression);
            Field varMapper = ValueExpressionImpl.class.getDeclaredField("varMapper");
            varMapper.setAccessible(true);
            VariableMapperImpl vmi = (VariableMapperImpl) varMapper.get(vei);
            if(vmi != null) {
                String[] components = exprString.split("\\.");
                components[0] = getMappedValueExpression(vmi.resolveVariable(components[0])); 
                ret = "";
                for(int i = 0 ; i < components.length ; i++) {
                    if(i != 0) {
                        ret += ".";
                    }
                    ret += components[i];
                }
            }
        } catch (Exception ex) {
            logger.error("Exception lors du mapping de l'expression EL " + exprString, ex);
        } finally {
            return ret;
        }
    }

如果在 MyFaces 或 Mojarra 中有此解决方法的更简洁版本会很棒...

【问题讨论】:

    标签: jsf dynamic components el


    【解决方案1】:

    这是 JSF 中的一个已知错误。

    已在此处提交给 Mojarra 团队:https://java.net/jira/browse/JAVASERVERFACES-2089,并在此处提交给 MyFaces 团队:https://issues.apache.org/jira/browse/MYFACES-3168。我意识到这些错误报告的措辞并不完全符合您的期望,但它是同一个错误。如果您查看 cmets:

    Hi guys,
    
    I just hit this bug again while working on a client's code, and
    noticed Manfred had closed it as 'resolved'?
    
    Why was this considered 'resolved'? It's a real problem for me,
    stopping me doing things like...
    
    <h:dataTable value="#{companyImport.importFiles}" var="_importFile">
        <h:column>
            <h:outputText value="#{_importFile.name}:"/>
        </h:column>
        <h:column>
            <m:metawidget value="#{_importFile.import}"/>
        </h:column>
    </h:dataTable>
    
    ...because the m:metawidget cannot 'see' the #{_importFile} var.
    
    Can we please reopen, or at least explain why it is resolved?
    

    这些错误报告都没有取得太大进展。您可能想对它们发表评论,对它们投票,并为这个问题增加分量。

    【讨论】:

    • 是的,这似乎是同一个错误。我也会对 MyFaces 问题添加评论,也许会建议我将在几分钟内提供的 kludge 的“干净”实现。
    猜你喜欢
    • 2020-12-29
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    相关资源
    最近更新 更多