javax.el API中的变量

时间:2012-02-22 23:13:12

标签: java el

我真的不明白变量在javax.el中是如何工作的:

// Implemented by the EL implementation:
ExpressionFactory factory = ExpressionFactory.newInstance();

// Implemented by the user:
ELContext context = ...;

Object result = factory.createValueExpression(context1, "${foo.bar}", Object.class).getValue1(context);

为什么需要两次传递上下文。是否有可能通过两种不同的背景?哪个用于什么目的?预期结果是什么:

ValueExpression expr = factory.createValueExpression(context1, "${foo.bar}", Object.class).getValue(context2);

ExpressionFactory#createValueExpression / JSR-245的javadoc解释了:

The FunctionMapper and VariableMapper stored in the ELContext are used to resolve
functions and variables found in the expression. They can be null, in which case
functions or variables are not supported for this expression. The object returned
must invoke the same functions and access the same variable mappings regardless
of whether the mappings in the provided FunctionMapper and VariableMapper
instances change between calling ExpressionFactory.createValueExpression()
and any method on ValueExpression.

此外,“JSR-245 2.0.7 EL变量”解释说:

An EL variable does not directly refer to a model object that can then be resolved
by an ELResolver. Instead, it refers to an EL expression. The evaluation of that
EL expression gives the EL variable its value.

[...]

[...] in this [...] example:
<c:forEach var=“item” items=“#{model.list}”>
    <h:inputText value=“#{item.name}”/>
 </c:forEach>

在创建“#{item.name}”表达式时,“item”变量(在VariableMapper中)映射到某个ValueExpression实例,表达式绑定到此ValueExpression实例。如何创建ValueExpression以及它如何绑定到“model.list”的不同元素?该如何实施?有可能 创建一次ValueExpression并在每次迭代时重复使用它:

 <!-- Same as above but using immediate evaluation -->
 <c:forEach var=“item” items=“${model.list}”>
    <h:inputText value=“${item.name}”/>
 </c:forEach>

ValueExpression e1 = factory.createExpression(context,"#{model.list}");
variableMapper.setVariable("item", ??);
ValueExpression e2 = factory.createExpression(context,"#{item.name}");
for(Object item : (Collection<?>) e1.getValue(context)) {
   ??
}

或者是否有必要为迭代创建一个新的ValueExpression:

ValueExpression e1 = factory.createExpression(context,"#{model.list}");        
for(Object item : (Collection<?>) e1.getValue(context)) {
   variableMapper.setVariable("item", factory.createValueExpression(item,Object.class));
   ValueExpression e2 = factory.createExpression(context,"#{item.name}");
   Object name = e2.getValue(context);
   ...
}

1 个答案:

答案 0 :(得分:2)

  

为什么需要两次传递上下文。是否可以通过两个   不同的背景?哪个用于什么目的?

variableMapperfunctionMapper仅在分析时使用(factory.createMethod(...)),而在评估期间使用elResolver(expr.getValue(... ))。使用不同的上下文来解析和计算表达式很好。

  

创建“#{item.name}”表达式时,“item”变量为   映射(在VariableMapper中)到一些ValueExpression实例和   表达式绑定到此ValueExpression实例。这怎么样   ValueExpression已创建,它是如何绑定到的不同元素的   “model.list”?该如何实施?

首先:忘记“变量”。正如Javadoc中所解释的,它们的值是表达式,在解析时提供。将EL变量视为常量或宏。你无法重新定义它们,它们会被“烧毁”到表达中。

您需要的是EL解析属性的机制。在下面的工作示例中,我使用JUEL中的ELContext实现,只是为了简单起见并关注相关的EL用法:

import java.util.Arrays;
import java.util.List;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;

import de.odysseus.el.util.SimpleContext;

public class Sof9404739 {
  /**
   * Sample item
   */
  public static class MyItem {
    String name;
    public MyItem(String name) {
      this.name = name;
    }
    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
  }

  /**
   * Sample model
   */
  public static class MyModel {
    List<MyModel> list;
    public List<?> getList() {
      return list;
    }
    public void setList(List<MyModel> list) {
      this.list = list;
    }
  }

  /**
   * EL expression factory
   */
  static ExpressionFactory factory = ExpressionFactory.newInstance();

  public static void main(String[] args) {
    /**
     * Simple EL context implementation from JUEL
     */
    ELContext context = new SimpleContext();

    /**
     * Define the two expressions
     */
    ValueExpression listExpr =
      factory.createValueExpression(context, "#{model.list}", List.class);
    ValueExpression nameExpr =
      factory.createValueExpression(context, "#{item.name}", String.class);

    /**
     * This looks like a variable, but it isn't - it's a "root property"
     */
    context.getELResolver().setValue(context, null, "model", new MyModel());

    /**
     * Just for fun, initialize model's list property via EL, too
     */
    context.getELResolver().setValue(context, "model", "list",
        Arrays.asList(new MyItem("alice"), new MyItem("bob")));

    /**
     * Evaluate expressions like c:forEach
     */
    for (Object item : (List<?>) listExpr.getValue(context)) {
      /**
       * For each item, define the "item" (root) property
       */
      context.getELResolver().setValue(context, null, "item", item);
      System.out.println(nameExpr.getValue(context)); // "alice", "bob"
    }
  }
}