BeanShell
BeanShell是一个小型嵌入式Java源代码解释器,具有对象脚本语言特性,能够动态地执行标准JAVA语法。
BeanShell不仅仅可以通过运行其内部的脚本来处理Java应用程序,还可以在运行过程中动态执行你java应用程序执行java代码。因为BeanShell是用java写的,运行在同一个虚拟机的应用程序,因此可以自由地引用对象脚本并返回结果。
https://github.com/beanshell/beanshell
1、eval
在maven工程的pom.xml引入
<dependency>
<groupId>org.beanshell</groupId>
<artifactId>bsh-core</artifactId>
<version>2.0b4</version>
</dependency>
对脚本进行反射式访问的最简单形式是通过 eval() 命令....
eval返回值为Object,可以通过eval()求文本表达式的值或者运行脚本,生成的任何异常都被捕获在 bsh.EvalError 中
Object eval ( String expression )
Note:不需要添加尾部“;”BeanShell 总是在字符串末尾加semi-colon(分号)
举例:
bsh(BeanShell)动态执行java代码
public static void main(String[] args) throws EvalError { Interpreter bsh = new Interpreter(); //循环打印变量 bsh.eval("for(int i=0; i<5; i++) { System.out.println(\"hello\"); }"); }
2、source
source()命令的作用与 eval() 命令完全相同,但从文件或 URL 源读取
//将文件名读入解释器并在当前命名空间中对其进行evaluate评估
Object source ( String filename )
Object source ( URL url )
把刚刚的"beanshell脚本"修改一下输出,放入一个文件中
String bshPath="C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh";
Interpreter bsh = new Interpreter();
//导入并执行一个脚本文件
bsh.source(bshPath); // or bsh.eval("source(\"myscript.bsh\")");
除了 EvalError 之外,Interpreter source() 方法还可能抛出 FileNotFoundException 和 IOException。
3、松类型变量
判断变量是否定义
if ( foobar == void ) // undefined
using the unset() command:
可以使用 unset() 命令将变量返回到未定义状态
a == void; // true a=5; unset("a"); // note the quotes a == void; // true
Java是强类型的语言,必须声明类型,但是 BeanShell松散类型,可以不用定义变量类型。
省略掉变量类型
foo = "Foo"; num = (2 + 3) * 10 / 2; System.out.println(foo + " = " + num);
运行结果:
Bsh 方法还可以允许动态(松散)参数和返回类型。
add( a, b ) { return a + b; } foo = add(1, 2); // 3 foo = add("Oh", " baby"); // "Oh baby"
4、set()和get()
可以使用 Interpreter set() 和 get() 方法将数据作为普通 BeanShell 变量传递到 Interpreter。
如将10赋值给num
interpreter.set("num", 10);
interpreter.set("date", new Date() );
通过get()方法去取得BeanShell中的变量
interpreter.get("num");
Date date = (Date)interpreter.get("date");
Interpreter interpreter = new Interpreter();
interpreter.set("num", 5);
interpreter.get("num");
对象
i.eval("myobject=object()" );
i.set("myobject.bar", 5);
数组
i.eval("ar=new int[5]");
i.set("ar[0]", 5);
i.get("ar[0]");
扩展:
unset()
可以使用 unset() 方法将变量返回到未定义状态。
5、脚本方法
可以声明和使用方法就像在Java中一样。
在main函数里执行脚本,并调用demo.bsh里的函数
public static void main(String[] args) throws EvalError, IOException {
String bshPath = "C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh";
Interpreter bsh = new Interpreter();
//导入并执行脚本
bsh.source(bshPath);
//调用脚本的函数
Object eval = bsh.eval("addTwoNumbers(2,8)");
System.out.println(eval);//10
}
扩展:获取脚本中定义了哪些方法
getMethods() 返回 bsh.BshMethod 对象的数组,这些对象是 BeanShell 脚本方法的内部解析表示形式的包装器:
int addTwoNumbers( int a, int b ) { return a + b; } //打印此命名空间中定义的方法 System.out.println(this.namespace.getMethods());
java 反射 API 使用特殊的类值来表示基本类型,例如 int、char、boolean。这些类型是各自原始包装类中的静态字段。例如 Integer.TYPE、Character.TYPE、Boolean.TYPE。
要调用脚本方法,请调用其 invoke() 方法,并传递参数数组、解释器引用和“callstack”引用。
int subTwoNumbers( int a, int b ) {
System.out.println("调用方法subTwoNumbers");
return a - b;
}
//查找定义的方法
name="subTwoNumbers";
signature = new Class [] { Integer.TYPE, Integer.TYPE };
bshMethod = this.namespace.getMethod( name, signature );
//调用方法
bshMethod.invoke( new Object [] { new Integer(10), new Integer(2) },
this.interpreter, this.callstack );
6、添加第三方jar
需要使用的api为
//将指定目录或JAR文件添加到类路径中
void addClassPath( string | URL )
举例如下:
- addClassPath( "/home/pat/java/classes" );
- addClassPath( "/home/pat/java/mystuff.jar" );
- addClassPath( new URL("http://myserver/~pat/somebeans.jar") );
准备好我们的第三方jar,如:fastjson.jar
在demo.bsh脚本中使用fastjson.jar中的方法
添加第三方jar的方法如下: interpreter.getClassManager().addClassPath(jarFile.getAbsoluteFile().toURI().toURL());
调用bsh脚本并执行
String bshPath = "C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh"; Interpreter bsh = new Interpreter(); //最关键的一步,添加第三方jar File jarFile = new File("E:\\tmp\\fastjson-1.2.29.jar"); bsh.getClassManager().addClassPath(jarFile.getAbsoluteFile().toURI().toURL()); //接着就可以在脚本中引入并使用了 bsh.source(bshPath);
运行结果如下
7、默认导入包
默认为您导入常用的Java核心包和扩展包,按照导入顺序,它们是
- javax.swing.event
- javax.swing
- java.awt.event
- java.awt
- java.net
- java.util
- java.io
- java.lang
java.awt.List and java.util.List 都是默认导入的
因为 java.util.List 是稍后导入的,作为 java.util 包的一部分,所以它优先。要访问 java.awt.List,只需将其导入,
使用List结构
Vector v = new Vector();
v.put(1);
int x = v.getFirstElement();
使用Map结构
// Use a hashtable
hashtable = new Hashtable();
date = new Date();
hashtable.put( "today", date );
// Print the current clock value
print( System.currentTimeMillis() );
8、EvalError
默认还导入了两个 BeanShell 包类
- bsh.EvalError
- bsh.Interpreter
bsh.EvalError 异常是评估 BeanShell 脚本时出现错误的一般异常类型
EvalError 的子类
- ParseException 由读取脚本时的语法错误引起的
- TargetError 脚本本身生成的异常,如NullPointer exception or an ArithmeticException
TargetError 包含“原因”异常。您可以使用 getTarget() 方法获取
try {
i.eval( script );
} catch ( TargetError e ) {
// The script threw an exception
Throwable t = e.getTarget();
print( "Script threw exception: " + t );
} catch ( ParseException e ) {
// Parsing error
} catch ( EvalError e ) {
// General Error evaluating script
}
您可以通过以下方法从 EvalError 中获取错误消息、错误的行号和源文件
String getErrorText() |
int getErrorLineNumber() |
String getErrorSourceFile() |
9、Parser类
1
public static void main(String[] args) throws FileNotFoundException {
FileReader in = new FileReader("E:/test.bsh");
Parser parser = new Parser(in);
while (!parser.Line()) {
SimpleNode node = parser.popNode();
if (node instanceof BSHMethodDeclaration) {
} else if (node instanceof BSHFormalComment) {
}
}catch(ParseException e){
System.out.println(e.getErrorSourceFile());
System.out.println(e.getErrorLineNumber());
System.out.println(e.getErrorText());
}
}
1
10、其他内置命令
https://beanshell.github.io/manual/contents.html
print()
print() 的作用与 System.out.println() 几乎相同,只是它确保输出始终进入命令行。 print() 还比 Java 更详细地显示某些类型的对象(例如数组)。
cat ( String filename )
打印文件的内容
bind ( bsh .This ths , bsh .NameSpace namespace )
将 bsh 对象绑定到特定的命名空间和解释器
clear ( )
清除此命名空间中的所有变量、方法和导入。如果此命名空间是根,它将重置为默认导入
void javap( String | Object | Class | ClassIdentifier )
打印指定类的字段和方法(输出类似于JDK javap命令)
如果参数是字符串,则它被视为类名。
javap( "java.util.Date" ); // String name of class
如果参数是对象,则使用该对象的类
javap( new java.util.Date() ); // instance of class
如果参数 是一个Class,则使用该类Class。
javap( java.util.Date.class ); // class
如果参数是类标识符,则将使用由类标识符标识的类
javap( java.util.Date ); // class identifier
exec()
运行本机应用程序
This object()
返回一个“空”BeanShell 对象上下文,可用于保存数据项
举例如下:
myStuff = object(); myStuff.foo = 42; myStuff.bar = "blah";
void save ( Object obj , String filename )
将可序列化的 Java 对象保存到文件
-------------------
Object load ( String filename )
从文件名加载序列化的 Java 对象。返回对象。
setAccessibility ( boolean b )
将可访问性设置为启用私有和其他非公共字段和方法。
setNameSpace ( ns )
设置当前作用域的命名空间(上下文)
fooState = object();
barState = object();
print(this.namespace);
setNameSpace(fooState.namespace);
print(this.namespace);
a=5;
setNameSpace(barState.namespace);
print(this.namespace);
a=6;
setNameSpace(fooState.namespace);
print(this.namespace);
print(a); // 5
setNameSpace(barState.namespace);
print(this.namespace);
print(a); // 6