java - javax.el API 中的变量

标签 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 实例,并且表达式绑定(bind)到这个 ValueExpression 实例。这个 ValueExpression 是如何创建的,它是如何绑定(bind)到“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);
   ...
}

最佳答案

Why is it needed to pass the context twice. Is it possible to pass two different contexts? Which is used for what purpose?

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

While creating the “#{item.name}” expression, the "item" variable is mapped (in the VariableMapper) to some ValueExpression instance and the expression is bound to this ValueExpression instance. How is this ValueExpression created and how is it bound to different elements of "model.list"? How should this be implemented?

首先:忘记“变量”。如 Javadoc 中所述,它们的值是在解析时提供的表达式。将 EL 变量视为常量或宏。您无法重新定义它们,它们已“嵌入”到表达式中。

您需要的是 EL 解析属性的机制。在下面的工作示例中,我使用了来自 JUELELContext 实现。 ,只是为了简单起见并专注于相关的 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"
    }
  }
}

关于java - javax.el API 中的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9404739/

相关文章:

jsp - jsp页面中的tomcat7和EL; pageContext.request.contextPath 为空?

java - 如何从表中的 struts 标记发送带有操作 URL 的参数

jsp - 在JSP中添加外部资源(CSS/JavaScript/图像等)

java - 如何在 JTextarea/JTextfield 中显示字符串

java - Spring Boot 应用程序中的 View 未渲染

java - 无法实现斯坦福 CoreNLP 的 OpenIE 注释器的选项

jsp - 如何在 JSF EL 中创建数组?

java - 设置 Eclipse 来学习 C 编程应该不难

java - 为什么出现java.lang.StackOverflowError : null when I try to print my entity

javascript - 调用 javascript 函数时出现错误