Skip to content

Commit 9101498

Browse files
committed
1.支持index模式取MAP节点,用于支持特殊符号节点名,例如req['content-type'],中括号中仅支持字符串格式,例如req[content-type]仍然按数组格式进行解析。
2.提供表达式变量分析工具,ELUtils.getVariants,将表达式传入后分析出该表达式的变量列表 3.修复根节点为数组时解析失败的问题,现在this[xxx]可以正确被识别为数组 4.优化了表达式方法调用选取重载方法的方式
1 parent afc36fd commit 9101498

File tree

15 files changed

+507
-182
lines changed

15 files changed

+507
-182
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<modelVersion>4.0.0</modelVersion>
1010
<groupId>net.fanjr.simplify</groupId>
1111
<artifactId>simplify-el</artifactId>
12-
<version>1.2.1</version>
12+
<version>1.3.0</version>
1313
<packaging>jar</packaging>
1414
<name>Simply Expression Language</name>
1515
<description>
@@ -49,7 +49,7 @@
4949
<dependency>
5050
<groupId>com.alibaba.fastjson2</groupId>
5151
<artifactId>fastjson2</artifactId>
52-
<version>2.0.49</version>
52+
<version>2.0.50</version>
5353
</dependency>
5454
<dependency>
5555
<groupId>org.slf4j</groupId>

src/main/java/org/fanjr/simplify/el/ELExecutor.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,12 @@ private static NodeInvoker resolveNode(char[] chars, int start, int end) {
744744
} else {
745745
int lastArrayIndex = findLastCharToken(chars, '[', start, end - 1, false);
746746
NodeInvoker parent = resolveNode(chars, start, lastArrayIndex);
747-
return IndexNodeInvoker.newInstance(nodeName, parent, resolve(chars, lastArrayIndex + 1, end - 1));
747+
ELInvoker indexEl = resolve(chars, lastArrayIndex + 1, end - 1);
748+
if (indexEl instanceof StringInvoker) {
749+
return IndexMapNodeInvoker.newInstance(nodeName, parent, (String) indexEl.invoke(null));
750+
} else {
751+
return IndexNodeInvoker.newInstance(nodeName, parent, indexEl);
752+
}
748753
}
749754
}
750755

@@ -758,8 +763,12 @@ private static NodeInvoker resolveNode(char[] chars, int start, int end) {
758763
}
759764
}
760765

766+
if ("this".equals(nodeName)) {
767+
// this关键字
768+
return RootNodeInvoker.INSTANCE;
769+
}
770+
761771
//其他情况为普通取节点值
762772
return MapNodeInvoker.newInstance(nodeName);
763773
}
764-
765774
}

src/main/java/org/fanjr/simplify/el/InnerFunctions.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
package org.fanjr.simplify.el;
22

3+
import com.alibaba.fastjson2.JSONObject;
4+
import com.alibaba.fastjson2.util.PropertiesUtils;
35
import org.slf4j.Logger;
46
import org.slf4j.LoggerFactory;
57

68
import java.io.Closeable;
79
import java.io.IOException;
810
import java.math.BigDecimal;
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
import java.util.Properties;
914

1015
/**
1116
* 内部函数,表达式通过$.方法名来调用,例如$.println(xxx)
1217
* 在这里配置 /src/main/resources/META-INF/simplify-el.functions
13-
* @author fanjr@vip.qq.com
1418
*
19+
* @author fanjr@vip.qq.com
1520
* @since 2024年4月17日 12:14:07
1621
*/
1722
public class InnerFunctions {
1823

1924
private static final Logger logger = LoggerFactory.getLogger(InnerFunctions.class);
2025

2126
/**
27+
* 日志框架输出
2228
* $.log(xxxxx)
2329
*/
2430
@ELMethod(order = Integer.MAX_VALUE)
@@ -27,6 +33,7 @@ public static void log(Object object) {
2733
}
2834

2935
/**
36+
* 控制台输出
3037
* $.println(xxxxx)
3138
*/
3239
@ELMethod(order = Integer.MAX_VALUE)
@@ -35,6 +42,7 @@ public static void println(Object object) {
3542
}
3643

3744
/**
45+
* 取两数大值
3846
* $.max(a,b)
3947
*/
4048
@ELMethod(order = Integer.MAX_VALUE)
@@ -43,6 +51,7 @@ public static BigDecimal max(BigDecimal a, BigDecimal b) {
4351
}
4452

4553
/**
54+
* 取两数小值
4655
* $.min(a,b)
4756
*/
4857
@ELMethod(order = Integer.MAX_VALUE)
@@ -51,6 +60,7 @@ public static BigDecimal min(BigDecimal a, BigDecimal b) {
5160
}
5261

5362
/**
63+
* 关闭资源
5464
* $.close(xx)
5565
*/
5666
@ELMethod(order = Integer.MAX_VALUE)
@@ -63,4 +73,55 @@ public static void close(Object obj) {
6373
}
6474
}
6575
}
76+
77+
/**
78+
* 获取枚举映射
79+
* $.getEnumMap(xx)
80+
*/
81+
@ELMethod(order = Integer.MAX_VALUE)
82+
public static Map<String, Enum<?>> getEnumMap(Object enumObject) {
83+
Map<String, Enum<?>> target = new HashMap<>();
84+
Class<?> enumClass;
85+
if (enumObject instanceof String) {
86+
try {
87+
enumClass = Class.forName((String) enumObject);
88+
} catch (ClassNotFoundException e) {
89+
throw new ElException("无法转换为枚举类型", e);
90+
}
91+
} else if (enumObject instanceof Class) {
92+
enumClass = (Class<?>) enumObject;
93+
} else if (enumObject instanceof Enum) {
94+
enumClass = ((Enum<?>) enumObject).getDeclaringClass();
95+
} else {
96+
throw new ElException("无法转换为枚举类型,无法获取对应映射关系!");
97+
}
98+
99+
if (enumClass.isEnum()) {
100+
Object[] enumConstants = enumClass.getEnumConstants();
101+
for (Object e : enumConstants) {
102+
String name = ((Enum<?>) e).name();
103+
target.put(name, (Enum<?>) e);
104+
}
105+
return target;
106+
} else {
107+
throw new ElException("无法转换为枚举类型,无法获取对应映射关系!");
108+
}
109+
}
110+
111+
/**
112+
* 深度合并多个MAP,若其中存在JSON数组则按照index进行合并,后面的MAP覆盖前面的
113+
* $.merge([map1,map2,map3...])
114+
*/
115+
@ELMethod(order = Integer.MAX_VALUE)
116+
public static Map<String, Object> merge(Map<?, ?>... maps) {
117+
JSONObject target = new JSONObject();
118+
for (Map<?, ?> map : maps) {
119+
Properties properties = PropertiesUtils.toProperties(map);
120+
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
121+
ELExecutor.putNode(target, String.valueOf(entry.getKey()), entry.getValue());
122+
}
123+
}
124+
return target;
125+
}
126+
66127
}

src/main/java/org/fanjr/simplify/el/InvokerMatch.java

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/main/java/org/fanjr/simplify/el/builder/ConversionBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public class ConversionBuilder {
3232
addBuilderByType("(double)", double.class);
3333
addBuilderByType("(String)", String.class);
3434
addBuilderByType("(BigDecimal)", BigDecimal.class);
35-
addBuilder("(class)", () -> new ELInvokerBuilder(1, ClassInvoker::buildInstance));
35+
// 出于安全考虑,不再内置提供将字符串转换为class的方法
36+
// addBuilder("(class)", () -> new ELInvokerBuilder(1, ClassInvoker::buildInstance));
3637
}
3738

3839
public static Supplier<ELInvoker> matchBuild(char[] chars, int start, int end) {
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package org.fanjr.simplify.el.invoker.node;
2+
3+
import com.alibaba.fastjson2.JSON;
4+
import com.alibaba.fastjson2.JSONObject;
5+
import com.alibaba.fastjson2.JSONReader;
6+
import com.alibaba.fastjson2.reader.ObjectReader;
7+
import org.fanjr.simplify.el.ELVisitor;
8+
import org.fanjr.simplify.el.ElException;
9+
import org.fanjr.simplify.utils.ElUtils;
10+
11+
import java.lang.reflect.Field;
12+
import java.util.Collection;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
public class IndexMapNodeInvoker extends NodeInvoker {
17+
18+
private final String indexNodeName;
19+
20+
private IndexMapNodeInvoker(String nodeName, NodeInvoker superNode, String indexNodeName) {
21+
super(nodeName);
22+
parentNodeInvoker = superNode;
23+
this.indexNodeName = indexNodeName;
24+
}
25+
26+
public static IndexMapNodeInvoker newInstance(String nodeName, NodeInvoker superNode, String indexNodeName) {
27+
return new IndexMapNodeInvoker(nodeName, superNode, indexNodeName);
28+
}
29+
30+
@Override
31+
Object getValueByParent(Object ctx, NodeHolder parentNode) {
32+
String nodeName = this.indexNodeName;
33+
if (null == parentNode) {
34+
return null;
35+
}
36+
Object parentValue = parentNode.getValue();
37+
if (null == parentValue) {
38+
return null;
39+
}
40+
if (parentValue instanceof Map) {
41+
return ((Map<?, ?>) parentValue).get(nodeName);
42+
}
43+
Class<?> parentClass = parentValue.getClass();
44+
if (parentClass == Class.class) {
45+
if (((Class<?>) parentValue).isEnum()) {
46+
return Enum.valueOf((Class<? extends Enum>) parentValue, nodeName);
47+
}
48+
} else if (parentClass.isEnum()) {
49+
try {
50+
Field field = parentClass.getDeclaredField(nodeName);
51+
field.setAccessible(true);
52+
return field.get(parentValue);
53+
} catch (Exception e) {
54+
return null;
55+
}
56+
} else if (parentClass == String.class) {
57+
String json = (String) parentValue;
58+
if (ElUtils.isBlank(json) || "null".equals(json)) {
59+
return null;
60+
}
61+
62+
char first = json.trim().charAt(0);
63+
if (first == '{') {
64+
try {
65+
JSONObject jsonObject = JSON.parseObject(json);
66+
parentNode.setChange(true);
67+
return jsonObject.get(nodeName);
68+
} catch (Exception e) {
69+
// 解析JSON字符串失败,不按照JSON进行解析
70+
// TODO 按临时解决方案,后续考虑更具性能的方案
71+
return null;
72+
}
73+
}
74+
}
75+
76+
return ElUtils.getFieldByPojo(parentValue, nodeName);
77+
}
78+
79+
@Override
80+
void removeValueByParent(NodeHolder parentNode, int index) {
81+
String nodeName = this.indexNodeName;
82+
if (null == parentNode) {
83+
return;
84+
}
85+
Object parentValue = parentNode.getValue();
86+
if (null == parentValue) {
87+
return;
88+
}
89+
if (parentValue instanceof Map) {
90+
((Map<?, ?>) parentValue).remove(nodeName);
91+
}
92+
93+
Class<?> parentClass = parentValue.getClass();
94+
if (parentClass == String.class) {
95+
//Parent类型为字符串,操作完后确保推送回Parent为字符串
96+
String json = (String) parentValue;
97+
if (ElUtils.isBlank(json) || "null".equals(json)) {
98+
return;
99+
} else {
100+
char first = json.trim().charAt(0);
101+
if (first == '{') {
102+
try (JSONReader reader = JSONReader.of(json)) {
103+
ObjectReader<JSONObject> objectReader = reader.getObjectReader(JSONObject.class);
104+
JSONObject jsonObject = objectReader.readObject(reader, 0);
105+
jsonObject.remove(nodeName);
106+
parentNode.setValue(jsonObject.toString());
107+
return;
108+
}
109+
} else {
110+
return;
111+
}
112+
}
113+
}
114+
115+
if (parentValue instanceof List || parentClass.isArray()) {
116+
// 不做处理
117+
return;
118+
}
119+
120+
ElUtils.putFieldByPojo(parentValue, nodeName, null);
121+
}
122+
123+
@Override
124+
void setValueByParent(NodeHolder parentNode, Object value, int index) {
125+
String nodeName = this.indexNodeName;
126+
if (null == parentNode) {
127+
throw new ElException("不可对【" + this + "】进行赋值!");
128+
}
129+
Object parentValue = parentNode.getValue();
130+
if (null == parentValue) {
131+
if (parentNode.isRoot()) {
132+
throw new ElException("ROOT节点为空!不可对【" + this + "】进行赋值!");
133+
}
134+
parentNode.setValue(JSONObject.of(nodeName, value));
135+
} else {
136+
if (parentValue instanceof Map) {
137+
((Map<String, Object>) parentValue).put(nodeName, value);
138+
if (parentNode.isChange()) {
139+
parentNode.setValue(parentValue);
140+
}
141+
return;
142+
}
143+
144+
Class<?> parentClass = parentValue.getClass();
145+
if (parentClass == String.class) {
146+
//Parent类型为字符串,操作完后确保推送回Parent为字符串
147+
String json = (String) parentValue;
148+
if (json.isEmpty() || "null".equals(json)) {
149+
parentNode.setValue(JSONObject.of(nodeName, value).toString());
150+
return;
151+
} else {
152+
char first = json.trim().charAt(0);
153+
if (first == '{') {
154+
try (JSONReader reader = JSONReader.of(json)) {
155+
ObjectReader<JSONObject> objectReader = reader.getObjectReader(JSONObject.class);
156+
JSONObject jsonObject = objectReader.readObject(reader, 0);
157+
jsonObject.put(nodeName, value);
158+
parentNode.setValue(jsonObject.toString());
159+
return;
160+
}
161+
}
162+
}
163+
}
164+
165+
if (parentClass.isArray() || parentValue instanceof Collection) {
166+
//打破原有结构
167+
JSONObject jsonObject = new JSONObject();
168+
jsonObject.put(nodeName, value);
169+
parentNode.setValue(jsonObject);
170+
return;
171+
}
172+
173+
if (ElUtils.putFieldByPojo(parentValue, nodeName, value)) {
174+
if (parentNode.isChange()) {
175+
parentNode.setValue(parentValue);
176+
}
177+
}
178+
}
179+
}
180+
181+
@Override
182+
public String toString() {
183+
return parentNodeInvoker.toString() + "['" + indexNodeName + "']";
184+
}
185+
186+
@Override
187+
public boolean isVariable() {
188+
if (null == parentNodeInvoker || parentNodeInvoker instanceof RootNodeInvoker) {
189+
// 没有上层节点,或者上层节点为ROOT节点,说明当前节点为变量
190+
return true;
191+
}
192+
193+
// 上级节点为变量则当前节点也为变量
194+
return parentNodeInvoker.isVariable();
195+
}
196+
197+
@Override
198+
protected void acceptChild(ELVisitor visitor) {
199+
// skip
200+
}
201+
202+
}

0 commit comments

Comments
 (0)