SSTエンジニアブログ

SSTのエンジニアによるWebセキュリティの技術を中心としたエンジニアブログです。

デスクトップJavaアプリ開発を支える技術

こんにちは、SSTでWeb脆弱性診断用のツール(スキャンツール)開発をしている坂本(Twitter, GitHub)です。

先日、元々ExcelのVBAマクロで組まれていたメール送信ツールを、Windows用のデスクトップアプリとしてJavaで作り直す突貫工事を行いました。

今どきのアプリ開発ではクライアントアプリといったらAndroidやiOSのスマホアプリ開発がほとんどで、WindowsやmacOSで動くデスクトップアプリを作る機会は減っているように感じます。

そこで今回は「デスクトップJavaアプリ開発を支える技術」と題し、Javaでデスクトップアプリ(特に Windows 用)を作るときに活用しているツールを紹介したいと思います。

本記事を読んでいただき、「デスクトップアプリ開発も楽しそうだな」と興味を持っていただければ幸いです。 あるいは突貫工事でデスクトップアプリを作る必要に迫られたときに、「そういえば Java なら簡単にできるって記事あったよな・・・」と思い出していただければ更に幸いです。

1. なぜ今どきデスクトップアプリを作るのか

2020年代ともなると、新しく作るアプリは大抵はサーバサイドで動くWebアプリが基本でしょう。*1 それに加えて、ブラウザ上で高度なGUIを構築するフロントエンド JavaScript や、サーバサイドと連携するAndroid/iOSアプリを作ることも多いと思います。 今どきWindowsやmacOSのデスクトップ上で動くGUIアプリを作るのは少数派ではないでしょうか。

一方で、事業の内側(バックヤード)では、非エンジニアの作業者が手元で動かす「ちょっとしたツール」がアチコチで必要となります。 昔は「ちょっとしたツール」を作るのに Excel/WordのVBAマクロがピッタリでした。 非エンジニアでも、勉強すれば手軽に手元で自動化ツールや入力フォームを作れます。 また MS Office さえあればどこでも実行できて、サーバを用意する必要もありません。

弊社でもVBAマクロを活用して、「ちょっとしたツール」を作っていたのですが・・・ここ数年、徐々にマクロの実行許可が厳しくなってきました。 マクロの内容によっては「Aさんの環境では動くけど、Bさんの環境では動かない」ややこしいエラーが散発するようになり、「このままVBAマクロに依存し続けるのは厳しいかも」となりつつあります。

そこでVBAマクロで組まれた自動化やフォームアプリを他の言語で作り直すことになるわけですが、元が「ちょっとした手作りツール」なので、小粒なんですよね。 いちいちサーバアプリを用意してフロントJSかスマホアプリでGUI組んで・・・となると、開発コストがややオーバースペックなんです。 さらに作業者の手元のWordやExcelで動いていたので、リプレース後も同じように手元で動いてくれたほうが違和感がありません。

というわけでVBAマクロの移行先として、2020年代の今どきであってもデスクトップ(= GUI)アプリが有効な選択肢として出てくるわけです。*2

2. デスクトップアプリ開発言語としてのJavaのススメ

いざデスクトップアプリを作るとして、開発言語は何を使うのがいいでしょうか? GUIアプリを作るということは、テキストボックスやボタン、プルダウンメニューなどたくさんのGUIコンポーネントを組み合わせることになります。 よって、GUIコンポーネントを扱いやすい言語がオススメとなります。

.NET が得意な人であれば、Visual Studio を使って Windows 用のデスクトップアプリが作れます。 プログラミング言語によっては Tcl/Tk と連携するライブラリが用意されていて win/mac/linux マルチプラットフォームでGUIを作れるケースもあります。 Tcl/Tk 以外にも、Qt でクロスプラットフォームのGUIアプリ開発が可能となっていたり、あるいはオープンソースで独自のGUIライブラリが利用できるケースもあります。

というわけで、選択肢はそれなりにあるわけですが・・・自分のイチオシとしては、Java をオススメしていきたいと思います。(それも Java 17 以上)

Java をオススメする理由としては、言語やエコシステムとして良い意味で「枯れて」おり、大抵の疑問はググれば解決策が見つかるから、というのがあります。

それに加え、本記事では「デスクトップアプリを作る」という観点から以下のオススメポイントを紹介していきたいと思います。

  1. Swing という枯れたUIライブラリが標準でバンドルされており、win/mac/linux クロスプラットフォームで動く。
  2. WindowBuilder という Eclipse プラグインを使うと、Swingを使ったフォームレイアウトをGUIで直感的にデザインできる。
  3. Apache Maven Shade Plugin や jpackage など、実行ファイルやインストーラ生成のためのビルドツールが整っている。

3. Swing という枯れたUIライブラリ

Swing は 1998年に Java SE 1.2 の一部としてリリースされました。 そのため長い歴史の蓄積があり、良くも悪くも「枯れた」UIライブラリです。 「枯れた」技術のいいところとして、「ググれば大抵は解決策が見つかる」点が挙げられます。 公式ドキュメント含め解説記事も大量に見つかります。

Swing 参考資料の例:

VBAマクロで作られた入力フォームを突貫工事でデスクトップアプリに仕立てたい・・・そんなときに、ググれば大抵の解決策が見つかりサクサク実装を進められる Swing は心強い味方になるでしょう。

枯れた技術の困った点として、設計がまだまだこなれておらず「バッドノウハウ」が必要になったり、モダンな技術と比べて実装の手間がかかる点があります。 ただ、「バッドノウハウ」そのものはググれば大抵は対処方法が見つかりますので、随時対処していけばいいだけです。 実装の手間がかかる点については、大規模なアプリを組むなら問題になってきますが、VBAマクロで作られた自家製ツールの規模であれば大きな障害にはならないでしょう。

以上より、開発規模がほどほどであれば、Swingの「良い点」だけをメリットとして享受できるのがオススメする理由となります。

4. Eclipse WindowBuilder

Swing ではGUIコンポーネントを Java クラスとして new して、親コンポーネントに追加してGUIを構築していきます。

実際の例:

lblMailFromName = new JLabel("担当者名");
lblMailFromName.setToolTipText("メール本文に埋め込まれます。(※メールアドレス欄には埋め込まれません)");
panelMailForm.add(lblMailFromName, "2, 8");

txtMailFromName = new JTextField();
txtMailFromName.setToolTipText("担当者の名前を記述してください。");
txtMailFromName.getDocument().addDocumentListener(mailFormTextChangeListener);
panelMailForm.add(txtMailFromName, "4, 8, 3, 1, fill, default");
txtMailFromName.setColumns(10);

lblMailBodySignature = new JLabel("署名登録");
panelMailForm.add(lblMailBodySignature, "2, 10");

scrollPaneMailBodySignature = new JScrollPane();
panelMailForm.add(scrollPaneMailBodySignature, "4, 10, 3, 1, fill, fill");

txtaMailBodySignature = new JTextArea();
txtaMailBodySignature.getDocument().addDocumentListener(mailFormTextChangeListener);
scrollPaneMailBodySignature.setViewportView(txtaMailBodySignature);

このように Java のソースコードとしてGUIを構築していくわけですが、パッと見で「人手で管理するの無理じゃね?」ってなりますよね?自分はなりました。

そこで Eclipse WindowBuilder プラグインの登場です。

eclipse.dev

これを使うと、Swing用のGUIコンポーネントをマウスでドラッグ & ドロップすることで直感的にGUIを構築できます。 Visual Studio や VBA のフォーム編集機能を使ったことがある人なら、すぐに使いこなせると思います。

こうしたデザイナツールは人間によるソースコードのカスタマイズと相性が悪いケースも多いのですが・・・ WindowBuilder の場合、Javaのソースコードを解析してることもあってか、人間があちこちソースコードに手を加えても正しく表示してくれます。

このように、Eclipse WindowBuilder プラグインを使うことでGUIデザインもサクサク進められるのが Swing + Java をオススメする理由になります。

5. Apache Maven Shade Plugin

無事ソースコードが完成したとして、「実行ファイル」= Windows なら .exe をどう作るのか?がデスクトップアプリ開発のポイントになります。 Javaの場合、さらにその手前に「依存関係にあるjarファイルをどうするのか」という問題も立ちふさがります。

Javaではライブラリが .jar というファイル拡張子で配布されており、中にはコンパイル済みの .class ファイルが格納されています。 Maven や Gradle といったビルドツールではどのライブラリ(= jarファイル) に依存するかを設定ファイルで管理し、ビルドツールが自動でjarファイルをダウンロードしてビルドします。 さらにEclipseやVSCodeなどのIDE/エディタを使うことで、開発環境の中から依存ライブラリを自動で classpath に設定してアプリケーションをビルド & 実行することができます。

ところが、非エンジニアの人が手元で Excel/Word VBAマクロとして実行していたツールをリプレースするとなると、そうした人たちのPC環境に EclipseやらMaven/Gradleをごっそり入れてもらうことは非現実的です。

Javaの場合は二段階でこの問題に対処します。

  1. 依存関係にあるjarファイルをまとめ、アプリケーション全体として java -jar (jarファイル) として実行可能な単一 jar ファイルを作る。
  2. JDKが提供する jpackage コマンドを使って、↑のjarファイルとその実行に必要なJRE(Java Runtime Environment) をバンドルしたインストーラを作りそれを配布する。(Windows なら .msi)

Apache Maven Shade Plugin はこの1段階目、実行可能な単一jarファイルを作成するのに使います。

maven.apache.org

java -jar (jarファイル) として実行可能な単一jarファイルを作る方法は、以下の解説が参考になります。

maven.apache.org

Java のビルドツールとしては Maven と Gradle がメジャーどころです。 それぞれの特色は、Maven が老舗で枯れてて安定性と互換性重視、Gradle が先進的で開発も盛んだけど互換性に難アリ、というのが個人の印象です。 今回紹介したのは Maven 用のプラグインです。 Gradleは詳しくないのですが、おそらく同様のプラグインがあるのではないかと思われます。

今回題材としてるような「バックヤードで使うちょこっとしたツール開発」って、一度作ると数年は塩漬けになりがちです。 そして数年後、別の誰かが「ここ不便だから直します」と蓋を開けてまたソースコードをかき混ぜてくわけです。 そうした開発で新機能テンコ盛りのエッジな技術を使うと、数年後に蓋を開けたときに「そもそもライブラリがインターネットから消えていてビルドできない」「ビルドツールが古すぎてまずバージョンアップする必要があるが、バージョンアップしたら設定ファイルのあちこちで非互換のエラーがでてビルドできない」など様々な問題が噴出しがちです。 これが事業コアに関わる製品開発であれば、頑張って最新にキャッチアップする価値はあります。 けれどバックヤードで使うちょこっとしたツールの改修に、そこまで時間をかけるのは厳しいですよね。 自分の好みではありますが、そうしたキャッチアップコストにシビアな開発でこそ、多少不便でも枯れて安定性と互換性重視のツールセットを採用したほうが後々楽だと考えます。 数年後、久しぶりにビルドしてみるか~となったときに、変わらずそのまま素直にビルドできたほうが嬉しいですよね。*3

そんな次第で、本記事では Maven プラグインとして Apache Maven Shade Plugin を紹介しました。

6. jpackage + WiX Toolset

Apache Maven Shade Plugin で java -jar (jarファイル) として実行可能な単一 jar ファイルを作れました。 では Java 実行環境と jar ファイルをどうやって非エンジニアのPCに配布すればいいのか? それを解決するのが、Java 14 で追加されたパッケージングツールの jpackage です。

jpackage コマンドを使うと、プラットフォームごとのインストーラ作成ソフトと連携することで Windows 用の msi や exe, あるいは macOS用のインストーラや Linux の rpm/deb パッケージを生成できます。

docs.oracle.com

Windows用の .msi を作るにはオープンソースの WiX Toolset をダウンロードして展開し、PATHを通しておきます。

wixtoolset.org

jpackage + WiX Toolset で作成した .msi (MSIインストーラ) にはJava実行環境(JRE, Java Runtime Environment) と実行可能jarファイル、それらを連携して起動するためのラッパー実行ファイルが含まれます。 MSIインストーラによって適切な場所に JRE と jar ファイル、ラッパー実行ファイルが配置され、Windows であればスタートメニューやデスクトップショートカットも追加されます。 結果、通常のWindowsアプリと同様にインストールしてスタートメニューから実行することが可能になります。

このように非エンジニア向けのパッケージングツールまで整備されているのが、Javaをオススメする理由です。

jpackage の使い方については、以下の記事も参考になるので紹介しておきます。

rheb.hatenablog.com

rheb.hatenablog.com

なお jpackage 自体は Java 14 から使えますが、実際の開発であればその次のLTSである Java 17、あるいはそれ以降の最新版LTSを使うと良いでしょう。

7. jdepsによるパッケージサイズの削減

jpackage コマンドを使うと簡単に JRE をバンドルできますが、まるごとバンドルすると50MB以上とそれなりにサイズを取ります。

Java 9 で導入されたモジュール化を使うと、必要なモジュールだけを指定することでバンドルするJREのサイズを削減することが可能です。

jdeps を使って jar ファイルが必要としているモジュールを調べ、 jpackage コマンドのオプションでそれを指定することで必要なモジュールだけに絞った軽量なJREをバンドルできます。

以下の記事の「Java ランタイムの軽量化」でも紹介されていますので、参考にしてみてください。

jpackageの踏み入った使い方 - 赤帽エンジニアブログ

8. コード署名(未解決)

ここまで紹介してきたツールを使って、自分も社内ツールをMSIで生成し、バックヤードの人たちに配布してインストール&利用してもらっていたのですが・・・ jpackage で生成したMSIの配布で遭遇したトラブルが一個だけあります。

それが「コード署名」で、未署名のインストーラを実行する際に Windows Defender 等のセキュリティソフトが警告を出してくることがありました。 共有フォルダからコピーしてきたり、社内ポータルWebサイトからダウンロードしてきて実行すると、ほぼ確実に警告が出る印象です。

こればっかりは警告をスキップしてもらうしかないのですが、とはいえ習慣として身についてしまうのもよろしくないので、どうしたものかと悩み中です。 コード署名用の証明書もだいぶリーズナブルになってきたとは思うのですが、社内で使う自家製のちょこっとしたツール一つ一つにまでコード署名を行うのも・・・コストバランス的にどうしたものかと。

これについては現状未解決のままで、将来的に色々な選択肢を調査・検討していきたいと考えています。

9. その他の選択肢

今回は Java + Swing を中心にオススメ技術、ツールを紹介してきました。

紹介した背景として、VBAマクロで作られた自家製ツールを移行するというコンテキストがあります。 業務用で特定の社員が内々で使うだけの、小規模ツールを突貫工事で作る必要に迫られたときならコレ!という観点でのオススメツールセットになります。

では、そうでないコンテキストではどうなるか? 例えば製品として販売したり、社外も含め大々的(何百人、何千人規模)に配布するような大規模なデスクトップアプリケーションを作るとしたら・・・

そのような場合ですと、以下のような選択肢が出てくると思います。

  • Eclipse RCP (Rich Client Platform)
    • https://wiki.eclipse.org/Rich_Client_Platform
    • Eclipse の開発基盤で、文字通り機能豊富なクライアントアプリを開発するための基盤です。
    • Eclipse のような高機能アプリ(表現力豊かで統一されたGUIコンポーネントとフレームワーク、プラグイン機構、アップデート機構)を作るならコレが選択肢に入ってくるでしょう。
  • JavaFX
    • https://openjfx.io/
    • 最新のクライアントアプリ開発用UIツールキットとフレームワーク。
    • XMLとCSSでレイアウトやデザインをカスタマイズ可能で、アニメーションや柔軟なUIを実現可能。
    • 業務アプリで出てくるような古典的なコンポーネントに囚われない、斬新なUI/UXを実現したいときはこれも選択肢に入ってくるでしょう。

Java言語以外に目を向ければ、Python では Qt 用ライブラリが老舗としてあり、また Python プログラムの exe 化ツールも複数選択肢があるようです。 JavaScript/Node.js エコシステムにおける Electron もモダンWebをそのままデスクトップアプリに仕立てられる点が魅力的です。

皆さんの得意なエコシステムに応じて、GUIアプリ開発やexe化の手法を探してみてください。


*1:Webアプリに限らずいろんな形態のアプリが増えてるとは思いますが、弊社でWeb診断事業をしている都合上、見える世界としてはWebアプリがほとんどになってるのでこうした表現になっております。

*2:こうしたいわゆる「シャドーIT」を情シス的なところで吸い上げてシステム化し、さらには業務フローそのものを見直してこうした小粒ツール/システムの必要性を抜本的に見直し、不要にするのが理想ではあります。が、まず現場の火消しをする上ではこうした ad-hoc 対応が必要なシーンもあり、まず対症療法を優先する舵取りもするイメージです。

*3:セキュリティの観点からは、使用しているツール・ライブラリ・言語の脆弱性情報を常に追いかけて最新にキャッチアップするのがベストです。ただ、インターネットに公開するわけでもなく、利用者も社内限定、PCで動くデスクトップアプリともなりますと、運用コストを鑑みてある程度妥協できるラインも出てくるかと思います。とはいえ、社内 = Trust Zone という考え方も通用しなくなってきていると思いますので、長期的にはやはり個々のツールをシステムにまとめ上げて、DevSecOpsを効率的に回していく仕組み作りが理想ではあります。