如何使用Spring Expression Language(或您知道的其他表达式语言)为定义为变量的某些对象的列表赋值

时间:2015-02-11 05:30:11

标签: java spring expression el spring-el

在Spel中,可以很容易地为List属性分配一些值。 例如,如果对象foo的属性定义为List,我通常会这样做:

SpelParserConfiguration config = new SpelParserConfiguration(true,true);
ExpressionParser parser = new SpelExpressionParser(config);
Foo foo = new Foo();
EvaluationContext context = new StandardEvaluationContext(foo);
parser.parseExpression("barList[1].test='11111111'")
    .getValue(context);

但是,对于要为给定List分配值的情况,您如何处理? 定义为方法中的变量。 e.g:

List<String> fooList = new ArrayList<String>();
context = new StandardEvaluationContext(fooList);       
parser.parseExpression("SOMETHING[0]='come on'")
.getValue(context);

在上面的例子中,我不知道要放什么而不是SOMETHING来使这项工作。 如果我输入“fooList [0] ='....'”,它会抛出一个异常,抱怨fooList中没有fooList属性。

如果我输入“[0] ='....'”,它会抛出无法增长的集合:无法确定列表元素类型。

然后我来定义这样的通用包装:

public static class SpelWrapper<T>
{
    T obj;

    public SpelWrapper(T obj)
    {
        this.obj = obj;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

然后尝试测试这个:

List<String> fooList = new ArrayList<String>();
    SpelWrapper<List<String>> no = new SpelWrapper<List<String>>(fooList);
    context = new StandardEvaluationContext(no);

    parser.parseExpression("obj[0]='olaaa'")
    .getValue(context);

但它没有用,仍然得到这个丑陋的信息:

Unable to grow collection: unable to determine list element type

我尝试了其他表达式语言,如MVEL,OGNL,JEXL,但我注意到它们不支持自动空引用初始化,这对我很重要。然而,他们似乎也无法解决上述问题。

我也开始思考如果我需要的不是表达语言的情况! 问题是我的需要不仅仅是定义变量并尝试使用EL分配值。

在我的例子中,我有一些简单的POJO域类bean和一些输入字符串,如

 "bar[0].foo.value=3434"

现在我应该能够创建Bar of Bar并将Bar实例作为其第一个元素,然后使用Foo实例设置foo属性,最后将Foo的值设置为3434.

关于这个问题的任何想法?

提前致谢

EIT 我错了“然而他们似乎也无法解决上述问题”。例如在MVEL中,这是一项非常容易的任务。但不幸的是,SPLE能够自动扩展列表并自动在空链中分配启动器,这使得它非常适合我的情况。

4 个答案:

答案 0 :(得分:1)

您必须在表达式中定义一个变量,并将其填入要处理的列表中,例如

context.setVariable("mylist", fooList);

然后你可以像这样访问它:

parser.parseExpression("#mylist.set(0)='come on'").getValue(context);

变量中的列表由反射使用;你可以打电话等方法 我希望这会有所帮助。

答案 1 :(得分:0)

问题是由于Java中的类型擦除,Spring或其他Els没有线索在包含列表的通用根对象的链中自动启动空值。 例如,在SpEl:

中的表达式中
#root[10].mySet='ohoy'

如果它检测到它需要首先启动ArrayList,则无法知道在给定索引处启动的正确元素Type是什么。 这就是为什么它需要一个包装来使用getter的返回类型的反映。

另一项工作是使用数组。因为数组组件类型保留在运行时。但问题是数组无法在运行时调整大小。 因此,它们需要以足够大的尺寸启动,以防止索引超出范围。

无论如何,为了做这些事情,类型擦除也是一个真正的痛苦,似乎他们(也适用于其他EL)仍然可以做一些努力围绕这个做一些工作。例如

1)如果列表不为空,则可以在运行时从中获取真实元素的类型。
2)更改getValue以获取泛型类型传递参数并将其用于启动 3)对于数组,返回展开的数组 4)......

虽然实现一个承诺处理所有启动或扩展的良好EL似乎是一项非常艰苦的工作,但我正在努力扩展Ognl以实现这一点。我从

开始
PropertyAccessor

并得到了一些非常有希望的结果。但是,在开发库时,我不知道apache有什么问题。例如,我不喜欢他们将处理程序放在Static类中的方式。我认为处理程序是一个上下文问题,但我不知道是否值得花费一些时间来扩展Ognl,但是一旦完成工作,我就会分享结果。

答案 2 :(得分:0)

根据this answer,以下方法应该起作用:

parser.parseExpression("obj").getValue(context, "olaaa"); // or is it "'olaaa'"?

甚至类似

parser.parseExpression("obj").getValue(context, "'olaaa', 'alooo'");

答案 3 :(得分:0)

就我而言,它是用户定义对象的数组列表。

上述解决方案均无效。

所以我一直在读到 arrayList 本身而不是对象的确切路径,一旦获取,我正在迭代和检查:-(

表达式 parsedValueExpression3 = parser.parseExpression("arraylist.root");

欢迎提出更好的建议。