我使用以下方法http://blog.kennardconsulting.com/2010/10/safely-manipulating-component-tree-with.html在PreRenderViewEvent上动态添加组件。
对于添加组件的组件来说,它工作得很好,但是当我尝试动态实例化ValueExpression-s时,我遇到了一个问题。
更具体地说,当我尝试使用动态传递的参数伪造动态ValueExpression时遇到问题。
让我们尝试解释一个例子...
在顶层,我使用标记组件(标记文件中描述的组件,而不是复合组件和自定义组件)。
<my:topComponent param=#{toto}"/>
在my:topComponent中,我将param传递给嵌套的组件。
<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似乎是未知的,因此将#{param2.code}评估为“null”。
我该怎么做才能纠正这个问题?调试时,我注意到getValueExpression(“finalParam”)设置了VariableMapper,而dynExpression没有设置(空值)
如果我做对了,则使用此VariableMapper将param2转换为param。
如何实例化我的动态表达式,以便保留VariableMapper(s)链?问题与FunctionMapper相同。
提前致谢。
更新
我同意理查德·肯纳德的回答:似乎是同样的错误。
由于我等不及几年的修复,因此我使用以下kudge递归地解析变量。它适用于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中的一个已知错误。
它已在Mojarra团队https://java.net/jira/browse/JAVASERVERFACES-2089和MyFaces团队https://issues.apache.org/jira/browse/MYFACES-3168提交。我意识到这些错误报告的措词不完全符合您的期望,但这是相同的错误。如果您查看评论:
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?
这些错误报告均未取得太大进展。您可能想对它们发表评论,对它们进行投票,并加深对这一问题的关注。