Javaはスクリプト言語だ — JBangが変えるJava開発の未来
JJUG CCC 2025 Springにて「Javaはスクリプト言語だ — JBangが変えるJava開発の未来」という発表をさせていただきました。
当日の発表スライドとデモコードはこちらに公開しています。
忘れないうちに、話した内容をここに記事にしておこうと思います。
JBang
JBangは、Javaをスクリプトのように直接実行できるツールです。
なぜJBang?
Javaで開発をしていると、ちょっとしたライブラリやAPIの挙動を検証したくなるときがあります。
開発中のプロジェクトにそうした検証コードを直接書いたりするのは嫌なので、通常は新たに検証用のプロジェクトを作ることになります。IDEやコマンドラインからJavaのプロジェクトを作り、pom.xml
やbuild.gradle
をいじって必要なプロジェクト設定と依存関係を追加し、やっと検証コードを書けるようになります。
Javaはビルドや実行は非常に速く快適ですが、このプロジェクトを作る部分が地味にフットワークが重くなります。JBangを使うと、コマンドラインからスクリプトを1つ生成するだけで、すぐにVimやEmacsなどのお好みのエディターでコードを書き始めることができます。
そしてJBangを使い込んでくると、1プロジェクト分の情報量を1スクリプトに凝縮して詰め込めるようになります。つまり、1スクリプト = 1プロジェクトの感覚でJavaコードを書くことができます。
同時に重要なのは、JBangはスクリプト的な手軽さはあっても、実行ランタイムはあくまで本番環境と同じJVMだということです。手軽に開発、検証を始められながら、ビルドして得られる実行コードは本番環境と同じ速度と堅牢性を備えています。
さらに、IDEとの連携や、スクリプトの配布方式などのエコシステムも充実しています。スクリプト的に書きなぐっていたところから、その先に発展させるパスも用意されています。そのため、マイクロサービス的な開発にも向いているでしょう。
このようにJBangを使い続けていると、単なる便利ツールでなく次世代のJava開発環境のように見えてきます。スモールスタートで始めてそこからフルスペックの開発に発展させる、あるいはサンプルコード、検証コードなどのチームで共有するナレッジベースを効果的に構築する、そういったことを実現する新しいプラットフォームです。
インストール
JBangのダウンロードページに様々なインストール方法が示されています。
curl
curl -Ls https://sh.jbang.dev | bash -s - app setup
sdkman
sdk install jbang
homebrew
brew install jbangdev/tap/jbang
はじめる
init
init
コマンドを使ってスクリプトファイルを作ります。
jbang init hello.java
スクラッチから書き始めてもいいですが、init
を使うとシェルスクリプトのように実行するための作法が予め埋め込まれたスクリプトが生成されます。
run
init
で生成されたスクリプトは、シェルスクリプトのように直接実行可能です。
./hello.java
普通にjbang
コマンドから実行することもできます。
jbang hello.java
他にも色々と面白い実行方法がありますが、たとえばこのようにGistにスクリプトをアップロードしてそれをURLから実行することもできます。
jbang https://gist.github.com/tadayosi/43dc74403c7acce5384c23129fbeb918
build
JARにビルドもできます。ビルドしておけば、JBangがない環境でもJVMだけで実行できるようになります。
jbang build --build-dir <path> hello.java
native
GraalVMがインストールされていれば、ネイティブビルドも可能です。組み込み環境など、実行速度やフットプリントが気になるようなユースケースで有効です。
jbang build --build-dir <path> --native hello.java
ファイルヘッダーの秘密
init
で生成されたスクリプトを見ると、次のファイルヘッダーが定義されています。
これはシェルスクリプトのシバン(shebang) #!
をマネするハックです。リンク先の記事、Goクックブックでこのテクニックが説明されています。
仕組みは次の通りです。まず、シェルでスクリプトとして実行されて先頭行が読まれたときに、スラッシュ(///
)はパスの区切り文字として扱われるため、絶対パスで指定されたenv
を呼び出す命令として実行されます。つまり、
/usr/bin/env jbang "hello.java" ""; exit $?
と同等です。次に、再帰的にjbang
コマンドが呼び出されたときには、先頭行のスラッシュ(//
)はJavaではコメント行なので、無視されてそこから先は有効なJavaソースとして実行されます。
これがJBangスクリプトのファイルヘッダーの秘密です。
依存のインポート
Javaの強みは、豊富なライブラリーによるエコシステムです。JBangでも、当然その強みを最大限活用できます。
ファイルのヘッダー部分にDEPS
というコメントタグを使うことで、依存ライブラリーをインポートできます。
指定の仕方は、いわゆるMavenのGAV (Group ID, Artifact ID, Version) 形式のコーディネートで指定します。Gradleを使ってる方はおなじみの形式です。
BOMも使える
JBangでは、依存ライブラリーのバージョンの後に@pom
を付けることでBOMを読み込めます。
この例では、SLF4JのBOMを読み込んでいます。それ以降、slf4j-api
やslf4j-simple
といったサブコンポーネントはバージョンを指定せずにインポートできます。
mcs
コマンド)
Maven Central Search (便利コマンドを1つ紹介します。
Maven Central Search (mcs
) というコマンドは、Mavenコーディネートの一部をキーに検索して、Maven Centralリポジトリーからその最新のバージョン一覧を取得してきてくれます。
$ mcs org.slf4j:slf4j-api
...
Coordinates Last updated
=========== ============
org.slf4j:slf4j-api:2.0.17 26 Feb 2025 at 01:43 (JST)
org.slf4j:slf4j-api:2.0.16 10 Aug 2024 at 18:15 (JST)
org.slf4j:slf4j-api:2.0.15 08 Aug 2024 at 21:59 (JST)
...
JBangとは直接関係のないツールですが、JBangで依存ライブラリーを調べるときに最適です。
リポジトリー
Mavenリポジトリーは、デフォルトではCentralを見に行きますが、社内のオフライン環境でイントラネット内のリポジトリーだけを参照したい場合や、製品ベンダーの特定のリポジトリーを使う必要がある場合などに、REPOS
コメントタグで指定できます。
//REPOS central,jitpack,myrepo=https://myrepo.local/maven
デフォルトで定義されてるcentral
、google
、jitpack
の他に、自分でmyrepo=https://myrepo.local/maven
のようにリポジトリーIDとURLのペアで指定することもできます。
名前 | 説明 |
---|---|
central |
https://repo1.maven.org/maven2/ |
google |
https://maven.google.com/ |
jitpack |
https://jitpack.io/ |
その他のタグ
そのほかJBangでサポートしているタグはたくさんありますが、独断で重要そうなものをピックアップすると以下の通りです。
//JAVA 21+
//COMPILE_OPTIONS --enable-preview --verbose
//RUNTIME_OPTIONS --add-opens java.base/java.net=ALL-UNNAMED
//NATIVE_OPTIONS -O1 -g
//PREVIEW
//MODULE <module-name>
//MAIN <main-class-name>
//MANIFEST Built-By=JBang
...
マルチファイル
依存ライブラリー読み込みの他に不可欠なのは、スクリプトから別のソースを読み込むことです。ロギングやSpring Boot、Quarkusのように、特別なリソースファイルを設定ファイルとして読み込む必要のあるフレームワークもあります。
ファイルを読み込むには、JavaソースならSOURCES
、リソースファイルならFILES
コメントタグを使います。
//SOURCES GreetingService.java
//SOURCES model/Person.java
//FILES application.properties
//FILES META-INF/resources/index.html=index.html
リソースファイルについては、META-INF/resources/index.html=index.html
のように=
を使って右側のローカルファイル (index.html
) を左側のパス (META-INF/resources/index.html
) として読み込ませることも可能です。Jakarta EE系のように、META-INF
以下にリソースファイルを置く必要のある場合に有効です。
IDEとの連携
依存ライブラリーやマルチファイルを使ってスクリプトを書いていると、IDEのコード補完などのサポートが欲しくなります。jbang edit
コマンドを使うと、JBangから指定のIDEを立ち上げることができます。
jbang edit greet.java
--sandbox
オプションを付けると、新たなサンドボックスプロジェクト(ディレクトリ)を作ってそこでIDEを開きます。スクリプトとそこから参照されているJavaソースおよびリソースファイルは、サンドボックスプロジェクトにシンボリックリンクとしてコピーされます。そのため、そこで編集した内容は元のソースコードに直接反映されます。
jbang edit --sandbox greet.java
さらに--no-open
オプションを付けると、IDEを開かず、サンドボックスプロジェクトのパスだけを返します。これをコマンドラインからIDEに渡して立ち上げることで、任意のIDEを使ってサンドボックスプロジェクトの編集を行えます。
$ jbang edit --sandbox --no-open greet.java
[jbang] Creating sandbox for script editing greet.java
/Users/tadayosi/.jbang/cache/projects/greet.java_jbang_6df7e8896068e72b39f45fca68fbb4c219e412c50af646bdfbfaa1472c26e429/greet
$ idea `jbang edit --sandbox --no-open greet.java`
IDEプラグイン
IDEのJavaサポートに加え、JBangエクステンション/プラグインをインストールすることで、DEPS
から依存ライブラリーをインポート(Synchronize JBang
)したり、Javaエディターから直接JBangスクリプトを実行(Run JBang
)、デバッグ実行(Debug JBang
)したりできるようになります。
以下がVS CodeとIntelliJのエクステンション/プラグインです。
エクスポート
さらに、JBangスクリプトでなく通常のJavaプロジェクトとして開発を続けたくなったら、MavenまたはGradleプロジェクトにエクスポートできます。
jbang export maven app.java
jbang export gradle app.java
指定したスクリプトの他、そこから参照されているJavaソースおよびリソースファイルがプロジェクトのソースコードとしてエクスポートされます。また、スクリプトに指定した依存ライブラリーがpom.xml
またはbuild.gradle
に追加されます。
実践編
ここまでがJBangの基本的な使い方でした。
実践編では、実際に私がこれまでJBangを使ってやってきたことを元に、JBangでどんなことまでできるのかを紹介します。
REST
ちょっとした検証や、システムの統合テスト用にモックのRESTサービスが必要になったときなどに、JBangを使って簡単にRESTサービスを実装できます。
Quarkus
Quarkusを使ったRESTサービスのスクリプトです。Quarkusのサポートにより、main
メソッドがなくてもこれだけでJBangからRESTサービスを起動できます。
Spring Boot
Spring BootでもRESTサービスを実装できます。Spring Bootではmain
メソッドが必要です。またコンポーネントスキャンの仕様上、デフォルトパッケージ以外のパッケージ名を使用する必要があります。
gRPC
gRPCの通信をテストするのにもJBangが使えます。次の.proto
ファイルから、gRPCで通信するクライアントとサーバーを実装してみます。
まず、protoc
コマンドを使って.proto
ファイルからProtocol BuffersのモデルクラスとgRPCスタブを生成する必要があります。
# モデルクラスの生成
protoc --java_out=. ./hello.proto
# gRPC Javaスタブの生成
protoc \
--plugin=protoc-gen-grpc-java=./protoc-gen-grpc-java-${GRPC_VERSION}-${OS}-${ARCH}.exe \
--grpc-java_out=. \
./hello.proto
サーバー
生成された以下のJavaソースファイルを読み込んで、HelloService
を実装したgRPCサーバーです。
- hello/Hello.java
- hello/HelloServiceGrpc.java
クライアント
同じく生成されたJavaソースファイルを読み込んで、gRPCクライアントを実装します。
AI/LLM
AIやLLMのテストや学習も、JBangを使って行えます。
DJL
Javaの深層学習フレームワークであるDJLを使ったサンプルスクリプトです。ここではAIモデルのMLPを使って、手書き数字の画像認識を行っています。
LangChain4j
最後に、LangChain4jとOllamaを使ったローカルで軽量LLMを動かすサンプルスクリプトです。Llama 3.2とLangChain4jのAIサービスの機能を使って、LLMにコーヒーの作り方を聞いています。
CLI開発
最後に、JBangのエコシステムとその機能について紹介します。それにはまず、CLI開発について触れる必要があります。
シェルスクリプトでちょっとしたCLI、コマンドラインツールを作るのは定番ですが、同様にJBangでCLIツールを作ることができます。
jbang init --template=cli cli.java
次のようなスクリプトの雛形が生成されます。
実行すると、すでに最低限のオプションがサポートされているのがわかります。
$ ./cli.java -h
Usage: cli [-hV] <greeting>
cli made with jbang
<greeting> The greeting to print
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
picocli
JBangのCLIテンプレートで使われているのは、picocliというCLIフレームワークです。
JBangベースのCLI
JBang + picocliを使って、実際にCLIを提供しているJavaのフレームワークやアプリケーションがあります。
カタログ
さらにJBangにはカタログという、スクリプト配布のための仕組みが備わっています。先ほどのCLI開発とこのカタログを組み合わせることで、JBangによるエコシステム構築の土台が出来上がります。
カタログとはjbang-catalog.json
という名前のJSONファイルです。これをGitHubリポジトリーhttps://github.com/user/repo
に置くと、
jbang my-cli@user/repo
のようにリポジトリーから直接スクリプトを呼び出すことができます。
とくにリポジトリー名をjbang-catalog
にすると、
jbang my-cli@user
のようにコマンド名@ユーザー名
だけでスクリプトを実行できます。
例
実際にApache CamelのJBangカタログを見てみましょう。
script-ref
で参照されているスクリプトは次の通りです。シンプルなスクリプトが、依存として特定バージョンのCamelライブラリーを読み込むことでCLIを起動します。
このCamel CLIは次のコマンドで起動できます。
jbang camel@apache/camel
アプリとしてインストール
それに加えてアプリという機能もあります。カタログのスクリプトを、コマンドとしてローカルにインストールできる機能です。
Camel CLIの例を使うと、次のようにするだけでcamel
コマンドをローカルにインストールできます。
jbang app install camel@apache/camel
camel --version
ここまでの機能によって、JBangのコード配布のエコシステムとしての仕組みが完成します。
公式カタログ
最後に、主要なベンダーでもJBangカタログを公開する流れが少しずつ増えています。
$ jbang catalog list
alibaba
https://github.com/alibaba/jbang-catalog/blob/HEAD/jbang-catalog.json
apache/camel
Run Apache Camel routes easily
https://github.com/apache/camel/blob/HEAD/jbang-catalog.json
jbangdev
JBang's own catalog of small utilities
https://github.com/jbangdev/jbang-catalog/blob/HEAD/jbang-catalog.json
jbanghub [importing]
JBangHub - Unleashing the Java community
https://raw.githubusercontent.com/jbanghub/jbang-catalog/main/jbang-catalog.json
jbanghub/apple
Apple cli's
https://github.com/jbanghub/apple/blob/HEAD/jbang-catalog.json
jbanghub/eclipse
Eclipse Foundation developed tools
https://github.com/jbanghub/eclipse/blob/HEAD/jbang-catalog.json
jbanghub/h2
H2 Database Engine
https://github.com/jbanghub/h2/blob/HEAD/jbang-catalog.json
jbanghub/jvm-profiling-tools
A collection of JVM profiling tools
https://github.com/jvm-profiling-tools/ap-loader/blob/HEAD/jbang-catalog.json
jbanghub/sqlline
Shell for issuing SQL to relational databases via JDBC
https://github.com/jbanghub/sqlline/blob/HEAD/jbang-catalog.json
jreleaser
Release projects quickly and easily with JReleaser
https://github.com/jreleaser/jbang-catalog/blob/HEAD/jbang-catalog.json
jupyter-java
Make it easy to use java from jupyter notebooks
https://github.com/jupyter-java/jbang-catalog/blob/HEAD/jbang-catalog.json
jvm-profiling-tools/ap-loader
Sampling CPU and HEAP profiler for Java featuring AsyncGetCallTrace + perf_events via JBang
https://github.com/jvm-profiling-tools/ap-loader/blob/HEAD/jbang-catalog.json
maveniverse
The missing pieces from Apache Maven universe
https://github.com/maveniverse/jbang-catalog/blob/HEAD/jbang-catalog.json
microsoft
Catalogue for JBang Artifacts
https://github.com/microsoft/jbang-catalog/blob/HEAD/jbang-catalog.json
oracle/graalpython
A Python 3 implementation built on GraalVM
https://github.com/oracle/graalpython/blob/HEAD/jbang-catalog.json
quarkusio
Subsonic and Subatomic Quarkus cli and plugins
https://github.com/quarkusio/jbang-catalog/blob/HEAD/jbang-catalog.json
日本からも、JBangカタログでJavaのコードを配布する動きが広まってくれるといいなと思います。
まとめ
これからのJava開発でJBangを使ってみよう、と思ってくれる方が少しでも増えたら幸いです。
とりあえずJBangをインストールして触ってみるだけでも楽しいので、ぜひ試してみてください。
Discussion