Home

Back

Contents

Next

Scripting Classes

Since BeanShell 2.0, in addition to the 'this' reference style of scripting objects and interfaces described in the previous section, you can also declare real Java classes and interfaces in your scripts using the ordinary Java class and interface keywords. A scripted class may extend another class (scripted or compiled) and implement any number of interfaces, just as it would in compiled Java. Instances of scripted classes are real instances of that class - they pass instanceof checks for the class and all of its superclasses and interfaces - which was not the case in earlier versions of BeanShell.

Declaring a Scripted Class

Constructors, instance and static fields, and instance and static methods all work as you would expect from Java. Method and constructor bodies are, of course, still loosely typed BeanShell code.

class Foo
{
    static int a = 5;
    int b;

    Foo() { }             // Foo needs a default constructor for Bar()
    Foo( int c ) { b = c; }

    void method() {
        print( "a is " + a );
    }

    static void smethod() {
        print( "static method, a is " + a );
    }
}

class Bar extends Foo
{
    method() {             // override, loosely typed
        print( "Bar.method() overrides Foo.method()" );
        super.method();     // call the overridden method
    }
}

Bar bar = new Bar();
print( bar instanceof Bar );  // true
print( bar instanceof Foo );  // true
bar.method();
Bar.smethod();                 // static members are inherited

As in Java, a subclass whose superclass does not have a no-argument constructor must define a constructor that calls one of the superclass's constructors explicitly.

Implementing Interfaces

You may also declare interfaces directly in a script, and implement them with the standard implements clause:

interface Named
{
    String getName();
}

class Person implements Named
{
    String name;
    Person( String name ) { this.name = name; }
    String getName() { return name; }
}

Named n = new Person( "Pat" );
print( n.getName() );

This works equally well with ordinary Java interfaces, including AWT and Swing listener types, giving you an alternative to the anonymous 'this' reference style described in "Scripting Interfaces" whenever you want a real, named, reusable class instead of an ad-hoc object.

Note:
The 'this' reference style of scripting objects and interfaces, described in the previous section, is still fully supported and remains the simplest way to script a one-off handler or adapter. Reach for a scripted class when you want inheritance, real instanceof behavior, or a type you intend to construct more than once.

Static Blocks

Static initializer blocks in the class body are supported:

class Foo
{
    static int a;
    static {
        a = 42;
    }
}

Persistent Scriptable Classes (Experimental)

Ordinarily a scripted class is generated dynamically, in memory, the first time it is referenced. Using the system property -DsaveClasses=<savedir> you can instead instruct BeanShell to write out a persistent .class file for each class definition it finds in a script. In this mode BeanShell does not execute the script; it only generates and stores the class files.

A class "Foo.class" generated this way expects to find its associated scripted class definition in a file "Foo.bsh" in the same location as the class file, so each stored class must have a corresponding script. For example, given:

// File: Foo.bsh
class Foo {
    Foo() { print("I'm being constructed!"); }
}

you can generate Foo.class in the current directory with:

java -DsaveClasses=. bsh.Interpreter Foo.bsh

The resulting Foo class may then be used like any ordinary Java class and invoked from ordinary Java code, e.g. new Foo(). When it is loaded it automatically starts a BeanShell interpreter to run its corresponding Foo.bsh script, so the script is still free to contain additional loose code beyond the class definition itself; that code runs when the class is initialized.

Note:
This feature is experimental. Each saved class currently initializes its own interpreter instance when loaded.

Current Limitations

A few corners of scripted classes are still incomplete:


Home

Back

Contents

Next