HomebrewのOpenJDKで jpackage が動かない理由

きっかけ

ある日、Java アプリケーションの macOS 向け配布パッケージを jpackage で作成しようとしたところ、エラーで処理が止まりました。

調べた結果、JAVA_HOME に指定していたのが Homebrew でインストールした OpenJDK だったことが根本原因でした。
Temurin に切り替えた途端、エラーは消えました。

この経験をきっかけに、Homebrew の OpenJDK と他のディストリビューションの JDK が何を違いとして持っているのかを整理しました。

ディレクトリ構造の違い

Homebrew OpenJDK — Linux 風 Flat 構造

Homebrew は Linux のパッケージ管理規約に倣った構造でインストールします。

/opt/homebrew/opt/openjdk/
├── bin/
├── include/
├── lib/
│   └── jvm/
└── libexec/
    └── openjdk.jdk/
        └── Contents/        ← 内部に隠蔽
            └── Home/

Apple が期待する macOS バンドルの構造は Contents/ を最上位に持ちますが、Homebrew はこれを libexec/ 以下に隠蔽しています。
/Library/Java/JavaVirtualMachines/ へのシンボリックリンクは張られるものの、jpackage のランタイム検出はリンク先の実体パスを参照するため、整合性が崩れることがあります。

Distribution JDKs(Temurin / Oracle / Microsoft)— Apple Bundle 構造

Cask 経由でインストールされる JDK は /Library/Java/JavaVirtualMachines/ に正規の macOS バンドルとして配置されます。

/Library/Java/JavaVirtualMachines/temurin-21.jdk/
└── Contents/
    ├── Home/          ← JAVA_HOME
    │   ├── bin/
    │   └── lib/
    ├── Info.plist     ← macOS バンドルメタデータ
    └── MacOS/

この構造は /usr/libexec/java_home による JDK 検出、jpackage のランタイムバンドル解決、codesign / notarytool のいずれとも完全に適合しています。

jpackage における具体的な問題

問題 原因 影響範囲
ランタイム検出失敗 Info.plist の欠如または不正なパス --runtime-image 指定時
コード署名エラー .app バンドル構造との不整合 Apple Silicon 含む全環境
Notarization 拒否 Apple ツールチェーンが期待する JDK 構造との乖離 配布パッケージ全般
jlink モジュールエラー symlink 越しのモジュールパス解決の失敗 カスタムランタイム生成時

シンボリックリンクとパス解決

Homebrew は /Library/Java/JavaVirtualMachines/ への symlink を提供していますが、jpackage 内部では realpath() による実体パス解決が行われます。
その結果、--runtime-image--jdk-path に渡したパスが期待する JDK バンドル構造と一致せず、エラーが発生します。

以下のコマンドで実体パスを確認できます。

$ readlink -f $(which java)
# Homebrew: /opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home/bin/java

$ /usr/libexec/java_home -V
# Temurin: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home

推奨される代替手段

jpackage を使うプロジェクトでは、以下のいずれかを使用してください。

  • Temurin(Eclipse Adoptium) — 最も実績が多く、CI/CD との相性も良好です
  • Microsoft Build of OpenJDK — Azure DevOps との統合が優れています
  • Oracle JDK — 商用サポートが必要な場合に適しています

まとめ

Homebrew の OpenJDK は開発・テスト・CI 実行用途では問題なく機能します。
しかし macOS 配布パッケージの生成(jpackage)、コード署名、Notarization が絡む場面では、Apple バンドル構造に準拠した JDK を使うべきです。

用途に応じて JDK を使い分けることが、macOS ネイティブ開発における現実的なアプローチです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください