Javax.el,ELResolver:解析变量之间的依赖关系

Javax.el,ELResolver:解析变量之间的依赖关系,java,variables,jboss,el,Java,Variables,Jboss,El,iam正在构建一个小型应用程序来处理变量。 第一步是解决变量之间的简单依赖关系。 我无法使事情正常运行。 我可以解析非常简单的声明,比如a=10,但如果它变得稍微复杂一点,就会失败,比如: a=b;b=10。 我将代码缩减为以下几行: import javax.el.BeanELResolver; import javax.el.ELContext; import javax.el.ELResolver; import javax.el.ExpressionFactory; import jav

iam正在构建一个小型应用程序来处理变量。 第一步是解决变量之间的简单依赖关系。 我无法使事情正常运行。 我可以解析非常简单的声明,比如a=10,但如果它变得稍微复杂一点,就会失败,比如: a=b;b=10。 我将代码缩减为以下几行:

import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.ValueExpression;
import javax.el.VariableMapper;

import org.jboss.el.ExpressionFactoryImpl;
import org.jboss.el.lang.VariableMapperImpl;


public void testEvalutation() throws Exception{

ExpressionFactory factory = new ExpressionFactoryImpl();    
ELContext context = new ELContext() {
  final ELResolver elResolver = new BeanELResolver();
  final VariableMapper variableMapper = new VariableMapperImpl();
  public ELResolver getELResolver() { return elResolver; }
  public FunctionMapper getFunctionMapper() { return null; }
  public VariableMapper getVariableMapper() { return variableMapper; }
};
ValueExpression a = factory.createValueExpression(context, "#{b}", Float.class);
ValueExpression b = factory.createValueExpression(context, "#{c}", Float.class);
ValueExpression c = factory.createValueExpression(context, "#{10}", Float.class);

context.getVariableMapper().setVariable("a",a);
context.getVariableMapper().setVariable("b",b);
context.getVariableMapper().setVariable("c",c);

ValueExpression expression = context.getVariableMapper().resolveVariable("a");
assertEquals(10f,expression.getValue(context));
}

“a”的结果为0.0。 有没有什么a做错了,或者你知道我运行代码的方法吗


感谢您的建议

我已经深入研究了EL实现,它对表达式创建和映射的顺序非常敏感

当创建时,它将解析表达式并使用绑定从此处解析的任何表达式。因此,当您设置a时,它将不会解析b,因为它尚未设置

结果,
#{b}
解析为null,然后强制为Float,结果为0.0

以下代码解析为值10.0:

请注意,这与从中解析变量时发生的情况不同


我使用了一个不同的实现(EL2.2;JavaEE6等价),但我希望JBoss实现中会有类似的行为。

我找到了一个解决方案,它可以像我需要的那样工作。它不依赖于排序,并以任何复杂度解析变量:

public class ElVariableResolver extends ELResolver  {
[...]
 protected final HashMap<String, Variable> variablesMap = new HashMap<String, Variable>();

 public ElVariableResolver(final Collection<Variable> variables) {
    this.variables = new HashSet<Variable>(variables);
    Iterator<Variable> iterator = variables.iterator();
    while (iterator.hasNext()) {
      Variable v = iterator.next();
      this.variablesMap.put(v.getName(), v);
    }
    [...]
    final FunctionMapperImpl functionMapper = new FunctionMapperImpl();
    this.expressionFactory = new ExpressionFactoryImpl();
    this.elContext = createELContext(this, functionMapper);
  }

 private static ELContext createELContext(final ELResolver resolver, final FunctionMapper functionMapper) {
    return new ELContext() {
      final VariableMapperImpl variableMapper = new VariableMapperImpl();
      @Override
      public ELResolver getELResolver() {
        return resolver;
      }
      @Override
      public FunctionMapper getFunctionMapper() {
        return functionMapper;
      }
      @Override
      public VariableMapper getVariableMapper() {
        return variableMapper;
      }
    };
  }

   public Object getVariableValue(final Variable variable) {
    String el;
    final Class<?> type;
    final String value = variable.getValue();
    switch (variable.getVariableType()) {
      case NUMBER:
        el = value.trim();
        type = Float.class;
        break;
      [...]
      final String expression = String.format("${%s}", el);
      ValueExpression ve = expressionFactory.createValueExpression(this.elContext, expression, type);
      Object result = ve.getValue(this.elContext);
      return result;
    }
  }

  @Override
  public Object getValue(ELContext context, Object base, Object property) {
    if ((base == null) && (property != null)) {
      Variable v = this.variablesMap.get(property);
      if (v != null) {
        return this.getVariableValue(v);
      }
    }
    return "TODO"; 
  }
}

public class ElVariableResolverTest extends TestCase{

  private final Variable l = new Variable("L",NUMBER,"M");
  private final Variable m = new Variable("M",NUMBER,"N");
  private final Variable n = new Variable("N",NUMBER,"10");
  private ElVariableResolver resolver;

  public void testEvaluation() {
    final List<Variable> variables = Arrays.asList(l,m,n);
    resolver = new ElVariableResolver(variables);
    assertEquals(new Float(10),resolver.getVariableValue("L"));
  } 
} 
公共类ElVariableResolver扩展了ELResolver{
[...]
受保护的最终HashMap变量smap=新HashMap();
公共ElVariableResolver(最终集合变量){
this.variables=新的HashSet(变量);
迭代器迭代器=变量。迭代器();
while(iterator.hasNext()){
变量v=迭代器.next();
this.variablesMap.put(v.getName(),v);
}
[...]
final FunctionMapperImpl functionMapper=新函数MapPerImpl();
this.expressionFactory=new ExpressionFactoryImpl();
this.elContext=createELContext(this,functionMapper);
}
专用静态ELContext createELContext(最终ELResolver解析器、最终FunctionMapper FunctionMapper){
返回新的ELContext(){
最终variableMapprimpl variableMapper=新的variableMapprimpl();
@凌驾
公共ELResolver getELResolver(){
返回解析器;
}
@凌驾
公共函数映射器getFunctionMapper(){
返回函数映射器;
}
@凌驾
公共VariableMapper getVariableMapper(){
返回变量映射器;
}
};
}
公共对象getVariableValue(最终变量){
字符串el;
最后的班级类型;
最终字符串值=variable.getValue();
开关(variable.getVariableType()){
案件编号:
el=value.trim();
类型=Float.class;
打破
[...]
最终字符串表达式=String.format(“${%s}”,el);
ValueExpression ve=expressionFactory.createValueExpression(this.elContext,表达式,类型);
对象结果=ve.getValue(this.elContext);
返回结果;
}
}
@凌驾
公共对象getValue(ELContext上下文、对象基、对象属性){
if((base==null)和&(property!=null)){
变量v=this.variablesMap.get(属性);
如果(v!=null){
返回此.getVariableValue(v);
}
}
返回“待办事项”;
}
}
公共类ElVariableResolverTest扩展了TestCase{
私有最终变量l=新变量(“l”,数字,“M”);
私有最终变量m=新变量(“m”,数字,“N”);
私有最终变量n=新变量(“n”,数字,“10”);
专用可变分解器;
公共资产评估(){
最终列表变量=数组.asList(l,m,n);
分解器=新的ElVariableResolver(变量);
assertEquals(新浮点(10),解析器.getVariableValue(“L”);
} 
} 

我注意到您只使用了一个。通常,您会创建一个,如中所示。您好,我已经阅读了您提到的示例,并在我的代码中尝试了类似的计算。如果我设置a=10和b=5,我可以创建一个类似${a+b}的表达式,它的结果是正确的:15。但是这个例子没有显示我如何链接变量a=b;b=10。即使有一个复合的解决方案,我仍然没有得到正确的结果。
public class ElVariableResolver extends ELResolver  {
[...]
 protected final HashMap<String, Variable> variablesMap = new HashMap<String, Variable>();

 public ElVariableResolver(final Collection<Variable> variables) {
    this.variables = new HashSet<Variable>(variables);
    Iterator<Variable> iterator = variables.iterator();
    while (iterator.hasNext()) {
      Variable v = iterator.next();
      this.variablesMap.put(v.getName(), v);
    }
    [...]
    final FunctionMapperImpl functionMapper = new FunctionMapperImpl();
    this.expressionFactory = new ExpressionFactoryImpl();
    this.elContext = createELContext(this, functionMapper);
  }

 private static ELContext createELContext(final ELResolver resolver, final FunctionMapper functionMapper) {
    return new ELContext() {
      final VariableMapperImpl variableMapper = new VariableMapperImpl();
      @Override
      public ELResolver getELResolver() {
        return resolver;
      }
      @Override
      public FunctionMapper getFunctionMapper() {
        return functionMapper;
      }
      @Override
      public VariableMapper getVariableMapper() {
        return variableMapper;
      }
    };
  }

   public Object getVariableValue(final Variable variable) {
    String el;
    final Class<?> type;
    final String value = variable.getValue();
    switch (variable.getVariableType()) {
      case NUMBER:
        el = value.trim();
        type = Float.class;
        break;
      [...]
      final String expression = String.format("${%s}", el);
      ValueExpression ve = expressionFactory.createValueExpression(this.elContext, expression, type);
      Object result = ve.getValue(this.elContext);
      return result;
    }
  }

  @Override
  public Object getValue(ELContext context, Object base, Object property) {
    if ((base == null) && (property != null)) {
      Variable v = this.variablesMap.get(property);
      if (v != null) {
        return this.getVariableValue(v);
      }
    }
    return "TODO"; 
  }
}

public class ElVariableResolverTest extends TestCase{

  private final Variable l = new Variable("L",NUMBER,"M");
  private final Variable m = new Variable("M",NUMBER,"N");
  private final Variable n = new Variable("N",NUMBER,"10");
  private ElVariableResolver resolver;

  public void testEvaluation() {
    final List<Variable> variables = Arrays.asList(l,m,n);
    resolver = new ElVariableResolver(variables);
    assertEquals(new Float(10),resolver.getVariableValue("L"));
  } 
}