GraalVM と
Picocliで
Javaのネイティブ
コマンドライン
アプリを作ろう

5秒で自己紹介

Remko Popma (レムコ ポプマ)

  • オランダ人、25年以上東京で滞在

  • SMBC 日興証券に勤務

  • Apache Log4j2 コミッターとPMC

  • Apache Groovy コミッター

  • コマンドラインアプリ用のライブラリ「picocli」の作成者

3つのポイント

  • picocliを使えば、コマンドラインアプリケーションを簡単に作れます

  • GraalVMで単一の実行可能なアプリケーションを作れます

  • picocliがGraalVMの弱点をカバーします

コマンドラインアプリ:   Java対Go-lang

Go vs Java

GraalVM ネイティブイメージ

Javaで単一の実行可能ファイル!

Holy Grail.shutterstock 268713941

「checksum」コマンドラインアプリ を作ろう

$ echo "hi" > hi.txt

$ checksum -a md5 hi.txt
764efa883dda1e11db47671c4a3bbd9e

$ checksum -a sha1 hi.txt
55ca6286e3e4f4fba5d0448333fa99fc5a404a73

ヘルプをつけよう

格好よくしよう: ASCIIカラーとASCIIアート!

checksum help ja

picocliで作ると簡単!

checksum source ja

単一の実行可能
ファイルを作ろう!

mervyn chan RFXxBTHze M unsplash

GraalVMとは何?

GraalVMはJavaで書かれた高性能のJVM

  • ネイティブイメージ:ahead-of-time(AOT)コンパイルしたアプリは一瞬で起動、メモリ使用の削減、単一の実行可能ファイルとして配布   できる!

  • 多言語:JavaScript, Python, Ruby, R, JVMベース言語(Java, Scala, Groovy, Kotlin, Clojure)や LLVMベース言語(C と C++)

  • 埋め込み可能(例:JNIなしでJavaとRを組み合わせられる)

GraalVMネイティブイメージの弱点

下記の機能を使用するとき、
コンフィギュレーションが必要:

  • リフレクション

  • リソース

  • ダイナミックプロキシ

picocliがアノテーションと リフレクションを使用する

// リフレクションでコマンド名、バージョン情報、記述などを読む
@Command(name = "checksum",
      version = "checksum 4.0",
  description = "ファイルのチェックサムを出力する。")
class CheckSum implements Callable<Integer> {

  @Parameters(index = "0",
        description = "このファイルのチェックサムを計算する")
  private File file; // リフレクションで値をセットする

  @Option(names = {"-a", "--algorithm"}, // リフレクションでオプション名を読む
    description = "MD5, SHA-1, SHA-256, ...")
  private String algorithm = "MD5"; // リフレクションで値をセットする

reflect.jsonの例

[
  {
    "name" : "CheckSum",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "fields" : [
      { "name" : "algorithm" },
      { "name" : "file" }
    ]
  },
  {
    "name" : "picocli.CommandLine$AutoHelpMixin",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "fields" : [
      { "name" : "helpRequested" },
      { "name" : "versionRequested" }
    ]
  }
]

picocli-codegenアノテーションプローセサーがコンパイル時にreflect-config.json
を生成。楽々!

$ mkdir classes
$ javac -cp .:picocli-4.0.3.jar:picocli-codegen-4.0.3.jar \
  -d classes CheckSum.java

$ tree classes
classes
├── CheckSum.class
└── META-INF
    └── native-image
        └── picocli-generated
            ├── proxy-config.json
            ├── reflect-config.json
            └── resource-config.json

ネイティブイメージを作ろう

$ /usr/lib/jvm/graalvm/bin/native-image \
    -cp classes:picocli-4.0.3.jar --no-server \
    --static -H:Name=checksum  CheckSum

単一の実行可能ファイルの
出来上がり!

サイズは 11MB

$ ll -h checksum
-rwxrwxrwx 1 remko remko 11M Sep  4 01:28 checksum*

実行は一瞬

$ time java -cp classes:picocli-4.0.3.jar CheckSum hi.txt

real    0m0.415s   ← 通常のJavaなら 415ミリ秒で起動
user    0m0.609s
sys     0m0.313s
$ time ./checksum hi.txt

real    0m0.004s   ← ネイティブイメージは 4ミリ秒で起動
user    0m0.002s
sys     0m0.002s

結論

GraalVMの用意をしましょう!

全ての main クラスはpicocliに値する!

リッチなドキュメンテーション

ありがとうございました

picocli を気に入ったら、GitHubで星をつけて、
友達に連携してください! ;-)

よろしくお願いします。