Programming ValueExpressions Instances

I dynamically add components to PreRenderViewEvent using the following http://blog.kennardconsulting.com/2010/10/safely-manipulating-component-tree-with.html method.

It works fine for the component adding the part, but I have a problem when I try to dynamically create ValueExpression expressions.

To be more specific, I have a problem when I try to create a dynamic ValueExpression using a dynamically passed parameter.

Let's try to explain an example ...

At the top level, I use a tag component (the component described in the tag file, not a composite, not a custom component.

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

In mine: topComponent, I pass the parameter to the nested component.

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

This nestedComponent uses a custom component (in my case, I get the component from Datatable primitives), passing param2 to it as another parameter ...

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

In customComponent, I dynamically add some child components to PreRenderViewEvent and set some ValueExpression expressions for customComponent.

Some of these expressions use finalParam. So, I expand the finalParam value and then create a new ValueExpression expression:

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

Then I create a dynamic value expression using this helper function:

 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; } 

Example:

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

In this example, the expression value is "# {param2.code}"

Then I can set this Expression value for my component:

 this.setValueExpression("rowKey", dynExpression); 

All this code is in a custom component class. I am using base class rendering.

However, the programmatically created ValueExpression is not correctly evaluated during rendering. For example, when a primitive processed by a datatable tries to calculate rowKey, # {param2.code} evaluates to "null" because param2 seems to be unknown.

What should I do to fix this? During debugging, I noticed that getValueExpression ("finalParam") has a VariableMapper set, and dynExpression does not (null value)

If I understood correctly, this VariableMapper is used to translate param2 into a parameter.

How can I instantiate a dynamic expression to keep the VariableMapper (s) chain? The question is the same for FunctionMapper.

Thanks in advance.

UPDATE I agree with Richard Kennard's answer: this seems like a mistake.

Since I can't wait years to fix, I use the following kludge to recursively resolve variables. It works for simple cases with my file 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; } } 

It would be great to have cleaner versions of this workaround in MyFaces or Mojarra ...

+4
source share
1 answer

This is a known bug in JSF.

This was served here with the Mojarra team: https://java.net/jira/browse/JAVASERVERFACES-2089 and here with the MyFaces team: https://issues.apache.org/jira/browse/MYFACES-3168 . I understand that the wording of these error reports is not quite what you expect, but it is the same error. If you look at the comments:

 Hi guys, I just hit this bug again while working on a client code, and noticed Manfred had closed it as 'resolved'? Why was this considered 'resolved'? It 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? 

None of these error reports have advanced. You can comment on them, vote for them and add weight to this issue.

+1
source

Source: https://habr.com/ru/post/1496120/


All Articles