【コラム】

Java API、使ってますか?

31 Javaの文法がそのまま使えるスクリプト言語"BeanShell"

31/60

JSR 274: The BeanShell Scripting Language

JSR 274で仕様の標準化が進められているBeanShellは、JavaVM上で動作するスクリプト言語である。文法がJavaのそれとほとんど同じという点が大きな特徴といえる。もちろん、動的な型付けに対応しているなど、スクリプト言語としての利点も兼ね揃えている。

文法でJavaと大きく異なる点は、クラスやインタフェースが定義できない点だ。ただし、Javaで書かれたクラスを呼び出すことができるため、自作のクラスが使えないというわけではない。また、Javaプログラム側からBeanShellスクリプトを実行するための機能も備えている。

BeanShellの実装そのものはすでにバージョン2.0のベータ版が公開されており、十分に実用レベルに達しているといっていい。JSR 274による仕様の標準化は、BeanShellの正式な構文や、最低限必要となるコマンドや実行環境などについて定義することを目的としている。

JavaVM上で動作するスクリプト処理系としては、BeanShell以外にもJSR 241で標準化が進められているGroovy、Rubyの実装であるJRuby、Pythonの実装であるJythonなどが有名。

BeanShellを試す

BeanShellの実装はこのページよりダウンロードすることができる。本稿執筆時点での最新版はバージョン2.0 beta 4(ファイル名bsh-2.0b4.jar)。

起動と基本的な使い方

起動はjavaコマンドで行う。BeanShellにはインタプリタモードとコンソールモードがある。ダウンロードしたファイルを任意のフォルダに配置したら、それをクラスパスに含めてコマンドプロンプトからプロンプト1またはプロンプト2のようにして起動する。

プロンプト1 インタプリタモードでの起動

> java -classpath [PATH_TO_JARFILE] bsh.Interpreter
BeanShell 2.0b4 - by Pat Niemeyer (pat@pat.net)
bsh %

プロンプト2 コンソールモードでの起動

> java -classpath [PATH_TO_JARFILE] bsh.Console

インタプリタモードでは、BeanShellはコマンドプロンプト上で動作する。コンソールモードの場合、図1のように内部にワークスペースを持つウィンドウが起動する。ワークスペースではインタプリタモードと同様にBeanShellスクリプトを実行できるほか、簡易なエディタや標準入出力のキャプチャなどといった機能を備えている。

図1 コンソールモード

BeanShellスクリプトの基本的な構文はJavaのそれを踏襲している。BeanShellそのものがJavaを使って記述されており、スクリプト中ではJavaのクラスが利用可能。たとえば最も基本となる「Hello BeanShell!」と出力したい場合はプロンプト3のように記述する。

プロンプト3 文字列を出力する例

bsh % System.out.println("Hello BeanShell!");
Hello BeanShell!

BeanShell独自の組み込みコマンドも用意されている。プロンプト3の例は、printコマンドを利用してプロンプト4のようにも書ける。

プロンプト4 独自のコマンドも用意されている

bsh % print("Hello BeanShell!");

Swingを利用したGUIプログラムはプロンプト5のような具合だ。この例の場合、図2のようなウィンドウが表示される。

プロンプト5 Swingを利用した例

bsh % import javax.swing.*;
bsh % JFrame f = new JFrame("BeanShell Sample");
bsh % f.getContentPane().setLayout(new FlowLayout());
bsh % JButton button1 = new JButton("Hello");
bsh % JButton button2 = new JButton("BeanShell!");
bsh % f.getContentPane().add(button1);
bsh % f.getContentPane().add(button2);
bsh % f.setSize(300, 200);
bsh % f.setVisible(true);

図2 ウィンドウの表示

スクリプトをファイルから読み込んで実行する場合は、runコマンドまたはsourceコマンドを利用する。プロンプト5の例で1行ずつ実行したスクリプトを「JFrameSample.bsh」というファイルにまとめて記述した場合(リスト1)、runコマンドでプロンプト6のように実行できる。

リスト1 JFrameSample.bsh

import javax.swing.*;

JFrame f = new JFrame("BeanShell Sample");
f.getContentPane().setLayout(new FlowLayout());

JButton button1 = new JButton("Hello");
JButton button2 = new JButton("BeanShell!");
f.getContentPane().add(button1);
f.getContentPane().add(button2);

f.setSize(300, 200);
f.setVisible(true);

プロンプト6 runコマンドでスクリプトを実行

bsh % run("JFrameSample.bsh");

sourceコマンドを利用した場合、スクリプト実行後のプロンプトで変数などの実行結果が有効になる。したがってプロンプト7のように、JFrameSample.bshを実行したままの状態で、内部で利用している変数にアクセスすることが可能。

プロンプト7 sourceコマンドでスクリプトを実行

bsh % source("JFrameSample.bsh");
bsh % f.setLocation(200,300);

多くのスクリプト言語と同様、動的な型付けにも対応しているため、JFrameSample.bshは型宣言を省略してリスト2のように記述することもできる。

リスト2 動的型付けにも対応

import javax.swing.*;

f = new JFrame("BeanShell Sample");
f.getContentPane().setLayout(new FlowLayout());

button1 = new JButton("Hello");
button2 = new JButton("BeanShell!");
f.getContentPane().add(button1);
f.getContentPane().add(button2);

f.setSize(300, 200);
f.setVisible(true);

当然、クラスパスさえ通っていれば自作のJavaクラスを利用することも可能だ。たとえばリスト3のようなクラスを作ったとすると、リスト4のようなスクリプトが実行できる。クラスのプロパティに対してはアクセッサメソッド(getXXXX())を用意することでアクセスできるようになっている。

リスト3 Point2D.java

public class Point2D {
        private double x;
        private double y;

        public Point2D(double x, double y) {
                this.x = x;
                this.y = y;
        }

        public double getX() {
                return this.x;
        }

        public double getY() {
                return this.y;
        }

        public void print() {
                System.out.println("(" + this.x + ", "+ this.y + ")");
        }
}

リスト4 自作Javaクラスの利用

point = new Point2D(100, 200);
point.print();
print("x = " + point.x);

Scripted MethodとScripted Object

メソッド(Scrioted Methodと呼ぶ)の定義はリスト5のように行う。distanceは先ほどのPoint2Dクラスを使い、2点間の距離を計算するメソッドである。

リスト5 メソッドの利用例

distance(p1, p2) {
        double xx = Math.pow(p2.x - p1.x, 2);
        double yy = Math.pow(p2.y - p1.y, 2);
        return Math.sqrt(xx + yy);
}

point1 = new Point2D(60, 40);
point2 = new Point2D(20, 10);
print(distance(point1, point2));

BeanShellではメソッドクロージャの役割を果たす「Scripted Object」を定義することができる。Scripted Objectは複数の変数/メソッドをまとめたもので、リスト6のように定義する。最後の「return this;」は必須で、これによって自身のオブジェクトを返す。このスクリプトを実行するとプロンプト8のような結果になる。

リスト6 ScriptedObjectSample.bsh

square(p, x, y) {
        Point2D point = p;
        double dx = x;
        double dy = y;

        printArea() {
                print("area = " + (dx * dy));
        }

        return this;
}

p1 = new Point2D(20, 50);
square = square(p1, 20, 30);
square.p.print();
square.printArea();

プロンプト8 ScriptedObjectSample.bshの実行例

bsh % run("ScriptedObjectSample.bsh");
(20.0, 50.0)
area = 600.0

Javaプログラムからの呼び出し

JavaプログラムからBeanShellスクリプトを呼び出すこともできる。BeanShellを構成するJavaクラスの中に「bsh.Interpreter」がある。インタプリタモードで起動するときに使うクラスだ。このクラスを利用することにより、Javaプログラム側からBeanShellスクリプトを実行できる。

具体的には、Interpreterのsource()メソッドまたはrun()メソッドにスクリプトのファイル名を渡せばよい。たとえばリスト7のような具合だ。

リスト7 ScriptCallSample.java - JavaプログラムからBeanShellスクリプトの呼び出し

import bsh.Interpreter;
import bsh.EvalError;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ScriptCallSample {
        public static void main(String[] args) {
                try {
                        Interpreter interpreter = new bsh.Interpreter();
                        Object result = interpreter.source("JFrameSample.bsh");
                }
                catch (FileNotFoundException e) {
                        e.printStackTrace();
                }
                catch (IOException e) {
                        e.printStackTrace();
                }
                catch (EvalError e) {
                        e.printStackTrace();
                }
        }
}

上記のように、BeanShellはJavaのために作られたスクリプト言語であり、Javaプログラムとの親和性が非常に高い。Java SE 6では標準でJavaScriptエンジンであるRhinoがバンドルされているが、Java SE 7ではそれ以外の言語の処理系も標準サポートに加えることが検討されており、その候補としてBeanShellの名前も挙がっている。Javaプラットフォームでのスクリプト言語サポートが強化される中、BeanShellを始めとしたJava系スクリプト言語にかけられる期待は大きい。

31/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。



人気記事

一覧

イチオシ記事

新着記事