beanshell

BeanShell

BeanShell是一个小型嵌入式Java源代码解释器,具有对象脚本语言特性,能够动态地执行标准JAVA语法。

BeanShell不仅仅可以通过运行其内部的脚本来处理Java应用程序,还可以在运行过程中动态执行你java应用程序执行java代码。因为BeanShell是用java写的,运行在同一个虚拟机的应用程序,因此可以自由地引用对象脚本并返回结果。

BeanShell - Introduction

https://github.com/beanshell/beanshell

1、eval

在maven工程的pom.xml引入

    
        org.beanshell
        bsh-core
        2.0b4
    

对脚本进行反射式访问的最简单形式是通过 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脚本"修改一下输出,放入一个文件中

beanshell_第1张图片

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

beanshell_第2张图片

在demo.bsh脚本中使用fastjson.jar中的方法

beanshell_第3张图片

添加第三方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

你可能感兴趣的:(python,开发语言)