java - 当 RHS 值解析集(varname,rhs)在 Apache JEXL3 中遇到运行时异常时如何访问 varname?
问题描述
对于 jexl 脚本中的以下语句,
routeX = Telemat.locate(map, vehicle, newLatLong);
使用该 JEXL 按以下顺序继续
- 解决 Telemat.locate(map, vehicle, newLatLong)。
- 查询 has('routeX'),以便我的 Java 代码知道声明了哪个 varname,并且如果 varname 已经存在,可以反馈给 JEXL。
- 调用方法 set('routeX', <resolved value of Telemat.locate(map, vehicle, newLatLong)> )
也就是说,RHS 之前已解析,调用了 has 或 get,因此我的 Java 代码在评估 RHS 时将不知道 LHS varname。
假设当地图无法访问时,我在 RunTimeException 中嵌入了 InAccessibleMapException 原因。碰巧的是,在某个情况下,地图无法访问。这导致 RunTimeException(InAccessibleMapException) 被抛出。
我有try-catch
try {
jexlScript.execute(script);
} catch (RunTimeException rte) {
// but my code does not know the varname.
}
当 JEXL 抛出异常时,我的 Java 代码需要向我工作的工程师反馈一条错误消息,其中包括导致脚本错误的 varname。
什么是最好的方法或策略,当在 RHS 解析期间引发异常时,我可以使用捕获 varname,以便异常捕获器可以在日志和错误消息中反馈除错误之外的 varname?
解决方案
最简单的方法是使用异常中的 JexlInfo 实例来尝试确定分配失败的变量。它不漂亮,但它应该在简单的情况下工作。
/**
* Finds the variable name (if any) when failing on assignment
* @param xany the exception
* @param script the script
* @return the variable name or "" if not found
*/
private static String seekVariable(JexlException xany, JexlScript script) {
JexlInfo info = xany.getInfo();
int line = info.getLine();
int column = info.getColumn();
String src = script.getSourceText();
int end = src.length();
int pos = 0;
// find absolute position
while (pos < end){
char c = src.charAt(pos);
if (line == 1) {
pos += column;
break;
}
if (c == '\n') {
line -= 1;
}
pos += 1;
}
boolean fail = true;
// crawl backwards to find '='
while(pos > 0) {
char c = src.charAt(pos--);
if (c == '=') {
fail = false;
break;
}
}
if (fail) return "";
fail = true;
// skip potential spaces
while(pos > 0) {
char c = src.charAt(pos);
if (!Character.isSpaceChar(c)) {
break;
}
pos -= 1;
}
int endName = pos;
int beginName = --pos;
// read varname
while(pos > 0) {
char c = src.charAt(pos);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
beginName = --pos;
}
return src.substring(beginName, endName + 1);
}
@Test
public void test339() throws Exception {
Map<String,Object> telemap = new HashMap<String,Object>() {
@Override public Object get(Object name) {
throw new IllegalStateException("inaccessible map");
}
};
JexlContext ctxt = new MapContext();
ctxt.set("tele", telemap);
ctxt.set("route", null);
JexlEngine jexl = new JexlBuilder().create();
String src = "route = tele.get('11')";
JexlScript script = jexl.createScript(src);
Object result;
try {
result = script.execute(ctxt);
} catch(JexlException xany) {
String varname = seekVariable(xany, script);
Assert.assertEquals("route", varname);
}
}
推荐阅读
- ios - 可以区分用户滚动和编程滚动吗?
- javascript - 我无法使用 NativeScript 在 jsPDF 中渲染图像
- python - Kinit 在 python 控制台中不起作用
- excel - 在 Excel 中绘制图形的公式
- javascript - Mongoose - 在文档中的特定日期执行函数
- php - 如何定义用于用户名而不是电子邮件的属性?
- python - ImportError:无法从“ecdsa”导入名称“SECP256kl”
- python - 如何控制经过身份验证的用户在 Django 中可以看到的内容?
- android - 在设备和桌面的不同位置查看的图像
- spring-boot - 当 Spring Boot 实例停止时,Spring Boot 客户端未从 Spring Boot Admin 注销