流中带有 "Collectors.toList()" 的 SpEL 解析参数不能用作 expressionString?

SpEL parsing parameters with "Collectors.toList()" in stream won't work as expressionString?

这会起作用

parser.parseExpression("#configList.stream().toArray()").getValue(context)

但以下不会

parser.parseExpression("#configList.stream().map(o -> o.ruleId).collect(Collectors.toList())").getValue(context)

F.Y.I上下文构造如下:

        Object[] args = joinPoint.getArgs();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String[] params = discoverer.getParameterNames(method);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < params.length; i++) {
            context.setVariable(params[i], args[i]);
        }

虽然 Java 可以在 SPeL 表达式中使用,但 SPeL 本身是一种独立的语言,并不 完全 支持 Java 语言。来自 documentation:

SpEL is based on a technology agnostic API allowing other expression language implementations to be integrated should the need arise.

要对SPeL表达式中的List进行过滤和映射操作,分别使用collection selection and collection projection

集合选择示例

// Java:
configList.stream().filter(o -> o.getRuleId() > 2).collect(Collectors.toList())

// SPeL (notice the question mark) :
"#configList.?[ruleId>2]"

集合投影示例

// Java:
configList.stream().map(o -> o.getRuleId()).collect(Collectors.toList())

// SPeL (notice the exclamation mark) :
"#configList.![ruleId]"

我已经建立了一个小例子来演示它:

public class So64738543ExpressionTest {
    public static class RuleItem {
        private int ruleId;

        public RuleItem(int ruleId) {
            this.ruleId = ruleId;
        }

        public int getRuleId() {
            return ruleId;
        }
    }

    @Test
    public void collectionProjection() {
        List<RuleItem> ruleItems = Arrays.asList(new RuleItem(1), new RuleItem(2), new RuleItem(3));
        EvaluationContext context = new StandardEvaluationContext(ruleItems);

        Expression expression = new SpelExpressionParser().parseExpression("#root.![ruleId]");
        Assert.assertEquals(Arrays.asList(1,2,3), expression.getValue(context));
    }
}

[编辑]

此外,如果 SPeL 表达式变得越来越复杂,我 强烈建议 将表达式移动到静态方法并使用 T operator 调用它。引用静态方法时不要忘记包含完全限定的包名称。