提取Spring Expression Language(SPEL)表达式中的变量

SPEL(Spring Expression Language)是Spring框架中的一种表达式语言,用于在运行时对对象图进行查询和操作。SPEL提供了一种简洁而强大的语法,允许开发人员在Spring应用程序中使用表达式来访问对象的属性、调用对象的方法、进行算术运算、逻辑运算等。

代码实现

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class SpringExpressionVariableExtractor {

private static final ExpressionParser PARSER = new SpelExpressionParser();
private static final TemplateParserContext PARSER_CONTEXT = new TemplateParserContext("${", "}");

private SpringExpressionVariableExtractor() {
}

public static Set<String> findVars(String templateStr) {
Expression expression = PARSER.parseExpression(templateStr, PARSER_CONTEXT);
List<VarDef> varSet = new ArrayList<>();
findOutVarByExpression(expression, varSet);
return mergeVars(varSet);
}

private static void findOutVarByExpression(Expression rootExpression, List<VarDef> varSet) {
if (rootExpression instanceof SpelExpression) {
SpelExpression spelExpression = (SpelExpression) rootExpression;
SpelNode spelNode = spelExpression.getAST();
findOutVar(spelNode, varSet);
} else if (rootExpression instanceof CompositeStringExpression) {
CompositeStringExpression compositeStringExpression = (CompositeStringExpression) rootExpression;
Expression[] expressions = compositeStringExpression.getExpressions();
for (Expression expression : expressions) {
findOutVarByExpression(expression, varSet);
}
}
}

private static void findOutVar(SpelNode node, List<VarDef> varSet) {
if (node instanceof PropertyOrFieldReference) {
varSet.add(new VarDef((PropertyOrFieldReference) node));
}
if (node.getChildCount() > 0) {
for (int i = 0; i < node.getChildCount(); i++) {
findOutVar(node.getChild(i), varSet);
}
}
}

/**
* 此处用于处理 #{serviceData.xxx.xxx} 这种变量的情况,Spring会解析为3个连续的PropertyOrFieldReference。首尾相接。
* <p>
* 处理思路:将变量信息入栈,入栈时获取栈顶元素,如果栈顶元素的结束位置+1 = 当前变量的开始位置,则合并这两个变量。
* </p>
*/
private static Set<String> mergeVars(List<VarDef> varDefList) {
Deque<VarDef> stack = new ArrayDeque<>();
for (VarDef varDef : varDefList) {
if (stack.isEmpty()) {
stack.push(varDef);
} else {
VarDef top = stack.peek();
if (top.end + 1 == varDef.start) {
top.merge(varDef);
} else {
stack.push(varDef);
}
}
}
return stack.stream().map(VarDef::getName).collect(Collectors.toSet());
}

@Data
private static class VarDef {

private String name;

private int start;

private int end;

public VarDef(String name, int start, int end) {
this.name = name;
this.start = start;
this.end = end;
}

public VarDef(PropertyOrFieldReference reference) {
this.name = reference.getName();
this.start = reference.getStartPosition();
this.end = reference.getEndPosition();
}

public void merge(VarDef def) {
this.name = this.name + "." + def.name;
this.end = def.end;
}
}

}

使用

1
2
3
4
5
6
7
public class Main2 {

public static void main(String[] args) {
Set<String> vars = SpringExpressionVariableExtractor.findVars("${type == 1 && serviceData.isComplete}");
System.out.println(vars);
}
}

运行结果

1
[serviceData.isComplete, type]

提取Spring Expression Language(SPEL)表达式中的变量

http://jaune162.blog/2024/03/01/extract-vars-of-spel.html

作者

大扑棱蛾子(jaune162@126.com)

发布于

2024-03-01

更新于

2024-09-11

许可协议

评论