torutkのブログ

ソフトウェア・エンジニアのブログ

JavaFXアプリケーションのJDK11対応(Windowsインストーラー作成編)

はじめに

JDK 10までは、JavaFXアプリケーションを配布する際に、ネイティブ・インストーラー形式にするjavapackager機能を使ってOS固有のインストーラーを作成することができました。Windowsネイティブなインストーラーを作成する際には、外部ツールとしてWiX Toolsetを使ってMSI形式のインストーラーを作成するか、同じく外部ツールとしてInnoSetupを使ってEXE形式のインストーラーを作成することができました。

しかし、JDK 11ではJavaFXとともにjavapackager機能が分離したため、JDK11上でのJavaFXアプリケーションは独自にインストーラーを作成することになります。

今回は、次のJavaFXアプリケーションをWindows OS上へインストールするMSI形式のインストーラーを作成していきます。gitのブランチは、jdk11 となります。masterは、JDK 8版のままです。

GitHub - torutk/AnalogClockGadget: JavaFX analog clock program to alternate for a desktop analog clock gadget

環境

項目 内容
OS Windows 10 64bit
JDK OpenJDK 11.0.1
インストーラー作成ツール WiX Toolset 3.10

WiX Toolsetの概要とインストール方法は、次のWikiページに記載しています。

http://www.torutk.com/projects/swe/wiki/WiX

JavaFXアプリケーションの実行イメージ作成

インストーラーを作成する前に、JavaFXアプリケーションの実行イメージをjlinkコマンドを使って作成しておきます。

D:\work\AnalogClockGadget> jlink ^
 --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1";build\modules ^
 --add-modules com.torutk.gadget.analogclock ^
 --launcher analogclock=com.torutk.gadget.analogclock/com.torutk.gadget.analogclock.AnalogClockApp ^
 --compress=2 --no-header-files --output runtime

D:\work\AnalogClockGadget> dir /w runtime
[.]       [..]      [bin]     [conf]    [legal]   [lib]     release

D:\work\AnalogClockGadget> 
  • JavaFXライブラリ(JMODモジュールファイル)と、ビルドしたアプリケーション(モジュール)を--module-pathオプションで指定します。
  • モジュール依存の基点となるJavaFXアプリケーション(モジュール)を--add-modulesオプションで指定します。
  • JavaFXアプリケーション実行用スクリプト/バッチファイルを生成するため、--launcherオプションでモジュールとエントリポイントクラス名を指定します。ここではスクリプト/バッチファイルの名称をanalogclockとし、モジュール名/エントリポイントクラス名を指定します。
  • 生成する実行イメージの大きさを小さくするため、--compressオプションでZIP圧縮(=2)を指定します。
  • 実行イメージにはJNI用のC/C++ヘッダーファイルを含まないよう--no-header-filesオプションを指定します。

生成されたruntimeディレクトリのbin\analogclock.bat を実行し、アプリケーションが起動することを確認します。

インストーラーの作成(第一歩)

WiX Toolsetを使って、JavaFXアプリケーションのインストーラーを作成します。まずは、最低限の機能だけを持つインストーラーを作成します。

インストーラー作成では、WiXXML文書を記述します。今回は、インストールする内容、インストール先ディレクトリを定義するAnalogClock.wxsファイルと、インストールするファイル群をheatコマンドで生成したruntime.wxsファイルを用意します。

WiXXMLドキュメント(AnalogClock.wxs)

AnalogClock.wsx(左端の▼印をクリックすると内容を表示/非表示)

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <Product Id="*" Name="Analog Clock" 
           Language="1041" Codepage="932" Version="0.4.1"
           Manufacturer="High Bridge" 
           UpgradeCode="fe287b25-e03d-4744-90f4-96b05dc36bf0">
    <Package Description="Analog Clock Gadget"
             Comments="(c) 2019 High Bridge"
             InstallerVersion="200" Compressed="yes"
             InstallScope="perMachine" />
    <MajorUpgrade DowngradeErrorMessage="既に新しい [ProductName]がインストールされています。"/>
    <MediaTemplate EmbedCab="yes" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFiles64Folder">
    <Directory Id="CompanyFolder" Name="High Bridge">
      <Directory Id="ApplicationFolder" Name="AnalogClock" />
    </Directory>
      </Directory>
    </Directory>
    
    <Feature Id="Product" Title="Analog Clock" Level="1">
      <ComponentGroupRef Id="RuntimeGroup" />
    </Feature>
  </Product>
</Wix>

Wix要素

WiXXML文書構造は、最上位の要素がWixで、Wix要素の属性で名前空間を指定しています。

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    :
</Wix>
Product要素

Wixの子要素にProduct要素を記述し、アプリケーション名などを定義します。

  <Product Id="*" Name="Analog Clock" 
           Language="1041" Codepage="932" Version="0.4.1"
           Manufacturer="High Bridge" 
           UpgradeCode="fe287b25-e03d-4744-90f4-96b05dc36bf0">
    :
    </Product>
  • Id属性にはGUIDを指定しますが、"*"を指定するとコンパイル時にGUIDが自動生成されます。インストーラーはこのGUIDが等しいと同じプログラムと認識します。新しいバージョンなどインストーラーを作り直した際はこのGUIDを変更する必要があります。
  • Name属性にはアプリケーション名を定義します。
  • Version属性にはアプリケーションのバージョン番号を定義します。通常ピリオドで区切った4つの数値を指定します。ただしMSIインストーラーはバージョンアップ判定時に4つ目の数字を無視することに留意が必要です。
  • Language属性とCodepage属性には、インストーラーが使用するロケール文字コードを定義します。日本語の場合は、Language属性に1041、Copdepage属性に932を指定します。
  • Manufacturer属性には開発元の組織名または開発者名を定義します。
  • UpgradeCode属性には同じアプリケーションで新しいバージョンを更新インストールする際の識別に使うGUIDを定義します。このGUIDは後々新しいバージョンのインストーラーを作成するときに継続して使用します。GUIDを生成する方法については、Windowsデスクトップ環境でUUID(GUID)を生成する方法 - torutkのブログ や、 GUIDの生成 に記載しています。
Package要素

Productの子要素にPackage要素を記述します。

        <Package Description="Analog Clock Gadget"
                 Comments="(c) 2019 High Bridge"
                 InstallerVersion="200" Compressed="yes"
                 InstallScope="perMachine"/>
  • Description属性とComments属性は、プログラムの説明、コメントを記載します。インストーラーファイルのプロパティ(詳細)で説明に表示されます。
  • InstallerVersion属性はMSIインストーラー(msiexec.exe)のバージョンを指定します。MSIのバージョンに2.0を指定する場合、"200"とします。現時点では4.5を指定("405")してもいいかと思います。MSI 4.5は、Windows Vista SP2、Windows Server 2008 SP2に標準搭載されています。
  • InstallScope属性は、全てのユーザーが使用できるperMachineか、インストールしたユーザーだけが使用できるperUserかを指定します。
  • Platform属性は、インストールするパッケージが64bit用であればx64を指定します。この属性でx64を指定すると、Component要素全てにWin64属性の指定が必要になります。そこで、64bitプログラムをインストールする場合は、この属性ではなく、candleコマンドの-archオプションでx64を指定します。
MajorUpgrade要素

新しいバージョンへ更新する仕組みを入れます。

<MajorUpgrade DowngradeErrorMessage="既に新しい [ProductName]がインストールされています。"/>

DowngradeErrorMessage属性には、既にインストールされたバージョンより古いバージョンをインストールしようとしたときにエラーメッセージとして表示する内容を定義します。

MediaTemplate要素

MSIファイルの中にCABファイルを含める場合に指定します(ふつう含めるので)。

        <MediaTemplate EmbedCab="yes" />
Directory要素

インストーラーでインストールする先のディレクトリ構造を定義します。 今回は、次のディレクトリにインストールするものとします。

C:\
  +-- Program Filse
        +-- High Bridge
              +-- AnalogClock

このディレクトリ構造に対応するDirectory要素の定義は次となります。

      <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFiles64Folder">
                <Directory Id="CompanyFolder" Name="High Bridge">
                    <Directory Id="ApplicationFolder" Name="AnalogClock" />
                </Directory>
            </Directory>
      </Directory>
  • ルートディレクトリ(ドライブ)は、Id属性にTARGETDIRを指定します。
  • 64bitアプリがインストールされるシステム共通のディレクトリは C:\Program Files ですが、これは事前定義名ProgramFiles64FolderをId属性に指定します。
  • C:\Program Filesの下に作成するディレクトリを指定します。
Feature要素
    <Feature Id="Product" Title="Analog Clock" Level="1">
      <ComponentGroupRef Id="RuntimeGroup" />
    </Feature>

Feature要素ではインストールする内容を定義します。今回は、インストールするファイル群をWiX Toolsetのheatコマンドで自動生成させるので、heatコマンドで作成するComponentGroupのIdを、ComponentGroupRefで参照する記述とします。なお、ComponentGroupのIdはheatコマンドのオプションで指定します。

WiX Toolsetコマンドの実行

heatコマンドでruntimeディレクトリ以下のファイル群から定義作成
D:\work\AnalogClockGadget> heat dir runtime ^
 -srd -dr ApplicationFolder ^
 -cg RuntimeGroup ^
 -gg -g1 ^
 -sfrag -sreg ^
 -var "var.runtimeFolder" -o runtime.wxs
  • 第1引数で収集対象をディレクトリ(dir)と指定します。
  • -srdオプションでルートディレクトリ(ここではdirオプションに続けて指定したruntimeディレクトリ)に対応するディレクトリの生成を抑制します。このオプションを指定しないと、インストール先ディレクトリ(C:\Program Files\High Bridge\AnalogClock)の下にruntimeディレクトリが作成され、その下にbinディレクトリ等が配置されます。 -drオプションで、インストール先ディレクトリのIdを指定します。今回はAnalogClock.wxs でAnalogClockプログラムをインストールするディレクトリとして定義したDirectory要素のIdに指定したApplicationFolderを指定しています。
  • -cgオプションで、生成するComonentGroupのIdを指定します。このIdは、AnalogClock.wxsのFeature要素の子要素ComponentGroupRefで参照されるので一致させる必要があります。
  • -ggオプションで各ComponentのGUIDを生成するよう指定します。
  • -ggオプションでGUIDを生成する際、波括弧を省略するよう指定します。
  • -sfragオプションでFragment要素をComponent要素毎ではなく、ComponentGroup要素に1つ生成するよう指定します。
  • -sregオプションで、DLLファイルに対するレジストリ情報収集(COMのDLLで必要)を抑制するよう指定します。64bit DLLのときにHEAT5150警告が出るのを抑制します。
  • -varオプションで、File要素のSource属性で指定するパスの基点となるフォルダを、変数として生成するよう指定します。このオプションを指定しないと、SourceDirという固定文字列がパスの基点となり、存在しないので後のlightコマンド実行時にエラーとなります。
  • -oオプションでディレクトリ以下のファイル群を収集した情報を吐き出すWiXファイル名を指定します。
candleコマンド

WiX文書ファイルをcandleコマンドでコンパイルし、wixobjファイル(中間ファイル)を生成します。

D:\work\AnalogClockGadget> candle -arch x64 package\windows\AnalogClock.wxs

D:\work\AnalogClockGadget> candle -arch x64 -druntimeFolder=runtime runtime.wxs
  • 64bitバイナリをインストールする場合は、-archオプションでx64を指定します。
  • -dオプションで、heatコマンドで、File要素のSource属性でファイルパスの基点を変数として生成した箇所に実際のパスを設定します。

実行結果、AnalogClock.wixobj と runtime.wixobjファイルが生成されます。

lightコマンド

Wix中間ファイルであるwixobjファイルから、lightコマンドでインストーラーファイルに生成します。

D:\work\AnalogClockGadget> light AnalogClock.wixobj runtime.wixobj -o analogclock.msi
  • 引数に、candleコマンドで生成したwixobjファイル(中間ファイル)をすべて指定します。
  • -oオプションで作成するMSI形式インストーラーのファイル名を指定します。

実行結果、analogclock.msiファイルが生成されます。ちなみに、ファイルサイズは38MBでした。

インストール

この第一歩のインストーラーは、必要最小限の機能しか設定していないので、インストーラーを実行すると対話(ダイアログ)画面もなく、所定のディレクトリにインストールするだけとなります。スタートメニューやデスクトップへのショートカット登録もありません。

analogclock.msiを実行すると、次のように経過を表示する画面が出てすぐに終了します。

f:id:torutk:20190103133822p:plain:w400
インストーラー(最初の一歩)実行画面(1)

f:id:torutk:20190103133853p:plain:w400
インストーラー(最初の一歩)実行画面(2)

プログラムを実行するには、インストール先のC:\Program Files\High Bridge\AnalogClock\bin\analogclock.batを実行します。

インストーラーの作成(第二歩)

第一歩で作成したインストーラーは、所定のディレクトリへプログラムをインストールするだけのものでした。 次は、スタートメニューのプログラム一覧にインストールしたJavaFXアプリケーションを起動するショートカットを追加する機能を盛り込みます。

Directory要素にスタートメニュー(プログラムメニュー)とサブフォルダ定義を追加

          <Directory Id="ApplicationFolder" Name="AnalogClock" />
        </Directory>
       </Directory>
+      <Directory Id="ProgramMenuFolder">
+          <Directory Id="ApplicationProgramsFolder" Name="High Bridge" />
+      </Directory>
     </Directory>

Directoryのルート要素の子要素に、Id属性でProgramMenuFolderを指定するDirectory要素を追加します。ProgramMenuFolderは事前定義名で、全ユーザー用のスタートメニューのプログラムディレクトリを示します。(C:\ProgramData\Microsoft\Windows\Start Menu\Programs)

そして、その下にアプリケーションのショートカットを収容するサブフォルダのDirectory要素を追加します。任意のId属性と作成するフォルダ名をName属性に指定します。

ショートカット要素を定義

プログラムを実行するショートカットを定義します。 DirectoryRef要素でショートカットを作成するフォルダを指定し、その子要素にComponent要素で囲ってShortcut要素を定義します。また、アンインストール用のRemoveFolder要素、Shortcut要素のKeyPath代替としてRegistryValue要素を定義します。

    <DirectoryRef Id="ApplicationProgramsFolder">
      <Component Id="ApplicationShortcut" Guid="*">
        <Shortcut Id="ApplicationStartMenuShortcut"
                  Icon="java.exe"
                  Name="Analog Clock Gadget"
                  Show="minimized"
                  Target="[ApplicationFolder]\bin\analogclock.bat"
                  WorkingDirectory="ApplicationFolder"/>
        <RemoveFolder Id="CleanUpShortcut"
                      Directory="ApplicationProgramsFolder"
                      On="uninstall" />
        <RegistryValue Root="HKCU"
                       Key="Software\[Manufacturer]\[ProductName]"
                       Name="installed" Type="integer" Value="1"
                       KeyPath="yes"/>
      </Component>
    </DirectoryRef>

    <Icon Id="java.exe" SourceFile="runtime\bin\java.exe" />
  • DirectoryRef要素のId属性は、先に定義したショートカットを収容するフォルダのId属性を参照
  • Comonent要素のId属性は、後でFeature要素の子要素に追加するComponentRefで参照する名前を指定
  • Shortcut要素
    • Icon属性でショートカットのアイコンを指定(アイコンをリソースに持つexeファイル等も指定可能)、icon要素のId属性を参照します。
    • Name属性はスタートメニューに表示されるショートカット名となるのでわかりやすい名前を指定
    • Show属性は、バッチファイルのショートカットを作成した場合に実行時にコマンドプロンプトが表示されるのを抑制するためminimizedを指定
    • Target属性はショートカットの対象ファイルを指定。Directory要素のIdで定義した名前を利用することができる
    • WorkingDirectory属性でショートカット実行時のカレントディレクトリを指定
  • RemoveFolder要素は、アンインストール時にショートカットフォルダを削除するための定義をしています。
  • RegistryValue要素は、Shortcut要素がKeyPath属性を持てない制約を解決するために、レジストリを使用します。
  • Icon要素は、Shortcut要素のIcon属性から参照され、ショートカットのアイコンを規定します。Idは対象ファイルと同じ拡張子を持つ必要があります。

Feature要素に追加

     <Feature Id="Product" Title="Analog Clock" Level="1">
       <ComponentGroupRef Id="RuntimeGroup" />
+      <ComponentRef Id="ApplicationShortcut" />
     </Feature>
  • Feature要素の子要素に、先ほどショートカット定義で作成したComonent要素のIdを参照するComponentRef要素を追加します。

インストールするとスタートメニューにショートカットが生成

f:id:torutk:20190104171628p:plain:w400
スタートメニューにショートカット

インストーラーの作成(第三歩)

第一歩、第二歩で作成したインストーラーは、インストールを実行すると一瞬ダイアログが表示されますがすぐに消えてインストールが完了してしまいます。

そこで、普通のインストーラーのように、インストール画面を表示し、ユーザーが操作するとインストールが進むようにします。

WiXでは、お仕着せの対話ダイアログがいくつか用意されているので、その中からニーズに合うものを選択することもできますし、カスタムの対話ダイアログを作ることもできます。今回第三歩では、お仕着せの対話ダイアログから最小限の対話を行うWixUI_Minimalを使用します。このWixUI_Minimalは、インストール時にライセンス表示を行い、ユーザーが確認をするとインストールが開始されます。

WiX定義にUIを追加

     </Feature>
+
+    <UIRef Id="WixUI_Minimal" />
+    <WixVariable Id="WixUILicenseRtf" Value="License.rtf" />
+
   </Product>

Product要素の子要素にUIRef要素を追加し、Id属性に事前定義済みWixUI_Minimalを指定します。

同じく、Product要素の子要素にWixVariable要素を追加し、Id属性に事前定義済みWixUILicenseRtfを指定、Value属性にRTF(Rich Text Format)形式で用意したライセンス許諾ファイルを指定します。アプリケーションのライセンスを記述したファイルをRTF形式で保存します。RTF形式は、Windows標準ツールのWordpadで作成可能です。

lightコマンドのオプション追加

- light AnalogClock.wixobj runtime.wixobj -o analogclock.msi
+ light AnalogClock.wixobj runtime.wixobj -o analogclock.msi -ext WixUIExtension

インストール実施

MSI形式のインストーラーファイル(第三歩版)を実行すると、ライセンス画面が表示されます。

f:id:torutk:20190104185259p:plain:w400
第3歩のインストーラー画面(1)

ライセンスを承諾すると、インストールが開始します。

f:id:torutk:20190104185329p:plain:w400
第3歩のインストーラー画面(2)

インストールが完了すると、インストール完了画面が表示されます。

f:id:torutk:20190104185359p:plain:w400
第3歩のインストーラー画面(3)

インストーラーの作成(第四歩)

こ個までの段階では、インストール先が固定となっています。今回は、インストール先を変更するダイアログを追加します。

WiX定義を変更(問題あり)

第三歩で追加した対話ダイアログ種類は、ライセンス表示とインストール結果表示を持つWixUI_Minimalでした。これを、インストール先変更表示を持つWixUI_InstallDirに変更します。 このWixUI_InstallDirを使うときは、アプリケーションをインストールするディレクトリを定義したDirectory要素のIdを、プロパティWIXUI_INSTALLDIRに指定する必要があります。

     </Feature>

-    <UIRef Id="WixUI_Minimal" />
+    <Property Id="WIXUI_INSTALLDIR" Value="ApplicationFolder" />
+    <UIRef Id="WixUI_InstallDir" />
     <WixVariable Id="WixUILicenseRtf" Value="License.rtf" />

インストール実施(問題あり)

インストールを実施すると次の画面が表示されます。

f:id:torutk:20190104213442p:plain:w400
第4歩のインストーラー画面(1)

ライセンス表示画面が表示されます。

f:id:torutk:20190104213515p:plain:w400
第4歩のインストーラー画面(2)

デフォルトのインストール先が表示されます。

f:id:torutk:20190104213547p:plain:w400
第4歩のインストーラー画面(3)

[Change]ボタンを押すと、ディレクトリ選択画面が表示されます。

f:id:torutk:20190104213610p:plain:w400
第4歩のインストーラー画面(4)

インストール準備完了の画面が表示されます。

f:id:torutk:20190104213632p:plain:w400
第4歩のインストーラー画面(5)

インストールの経過を示す画面が表示されます。

f:id:torutk:20190104213651p:plain:w400
第4歩のインストーラー画面(6)

インストールが完了した画面が表示されます。

f:id:torutk:20190104213712p:plain:w400
第4歩のインストーラー画面(7)

問題とは?

インストーラーでインストール先を変更したにも関わらず、インストール先はデフォルトのディレクトリとなってしまいました。

いろいろ調べてみたところ、WIXUI_INSTALLDIRプロパティで指定するディレクトリのIdの名前はすべて大文字とする必要があるということが判明しました。

WiX定義を変更(問題解決)

AnalogClock.wxsの変更箇所
     <Directory Id="TARGETDIR" Name="SourceDir">
       <Directory Id="ProgramFiles64Folder">
        <Directory Id="CompanyFolder" Name="High Bridge">
-         <Directory Id="ApplicationFolder" Name="AnalogClock" />
+         <Directory Id="APPLICATIONFOLDER" Name="AnalogClock" />
        </Directory>
       </Directory>
                   Show="minimized"
-                  Target="[ApplicationFolder]\bin\analogclock.bat"
-                  WorkingDirectory="ApplicationFolder"/>
+                  Target="[APPLICATIONFOLDER]\bin\analogclock.bat"
+                  WorkingDirectory="APPLICATIONFOLDER"/>
         <RemoveFolder Id="CleanUpShortcut"
     <UIRef Id="WixUI_InstallDir" />
+   <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONFOLDER" />
     <WixVariable Id="WixUILicenseRtf" Value="License.rtf" />
heatコマンド実行オプションの変更
 D:\work\AnalogClockGadget> heat dir runtime ^
- -srd -dr ApplicationFolder ^
+ -srd -dr APPLICATIONFOLDER ^
  -cg RuntimeGroup ^
  -gg -g1 ^
  -sfrag -sreg ^
  -var "var.runtimeFolder" -o runtime.wxs

インストール実施(問題解決)

インストーラーの画面に変更はありませんが、インストール先が無事変更できるようになりました。

jlinkで生成するランチャー(バッチファイル)の修正

jlink で--launcherオプションを指定すると、次のバッチファイルが生成されます。

@echo off
set JLINK_VM_OPTIONS=
set DIR=%~dp0
"%DIR%\java" %JLINK_VM_OPTIONS% -m com.torutk.gadget.analogclock/com.torutk.gadget.calendar.AnalogClockApp %*

このバッチファイルに2つの修正を加えます。

  1. 実行時にコマンドプロンプトが表示されたままとならないよう起動コマンドをjava.exeからjavaw.exeに変更
  2. CPU・メモリにやさしいプロセスとするべくコマンドラインオプションを追加

起動コマンドをjava.exeからjavaw.exeに変更

javaコマンドはコンソール(コマンドプロンプト)を伴うので、このランチャー(バッチファイル)を実行すると画面にコマンドプロンプトが表示されたままとなります。ショートカットでコマンドプロンプトを最小化する設定をしていますが、タスクバーにはコマンドプロンプトが残ったままとなります。

そこで、バッチファイルの中でjavaコマンドをjavawコマンドに修正し、コマンドプロンプトが残らないようにします。

  @echo off
  set JLINK_VM_OPTIONS=
  set DIR=%~dp0
- "%DIR%\java" %JLINK_VM_OPTIONS% -m com.torutk.gadget.analogclock/com.torutk.gadget.calendar.AnalogClockApp %*
+ start "" /b "%DIR%\javaw" %JLINK_VM_OPTIONS% -m com.torutk.gadget.analogclock/com.torutk.gadget.calendar.AnalogClockApp %*
  • startコマンドでjavawコマンドを起動します。最初の""がないと、startコマンドが"%DIR%javaw" をウィンドウタイトルとして扱い、エラーとなります。

CPU・メモリにやさしいコマンドラインオプションを追加

64bit版のjava(javaw)コマンドはデフォルトではCPU、メモリをがんがん使う設定となっています。 そこで、必要最低限のCPUとメモリ使用にすべく、JavaVMオプションを追加指定します。

  @echo off
-  set JLINK_VM_OPTIONS=
+ set JLINK_VM_OPTIONS=-Xms32m -Xmx64m -Xss256k ^
+ -XX:TieredStopAtLevel=1 -XX:CICompilerCount=2 -XX:CompileThreshold=1500 ^
+ -XX:InitialCodeCacheSize=160k -XX:ReservedCodeCacheSize=32m ^
+ -XX:MetaspaceSize=12m -XX:+UseSerialGC
  set DIR=%~dp0
  start "" /b "%DIR%\javaw" %JLINK_VM_OPTIONS% ^
  -m com.torutk.gadget.analogclock/com.torutk.gadget.analogclock.AnalogClockApp

オプションの意味・値などは次に簡単なまとめ記載 JDK 9 JavaVMオプション - ソフトウェアエンジニアリング - Torutk

まとめ

JavaFXアプリケーションをJDK11&モジュール(JPMS)対応した後に、Windowsインストーラーを作ってJava実行環境を含めて配布できるようにしました。

  • 作業環境は、Windows 10、OpenJDK 11.0.1、OpenJFX 11.0.1、WiX Toolset 3.10
  • jlink コマンドで、JavaFXアプリケーションとその実行に必要なモジュールを抽出して実行環境のイメージを作成
  • WiX Toolset で実行環境のイメージからMSI形式インストーラーを作成
    • AnalogClock.wxs ファイル(XMLドキュメント)を記述し、アプリケーションの情報、インストール先ディレクトリ、スタートメニューのショートカット、インストーラーのGUI種類などを定義
    • heatコマンドでjlinkが生成した実行環境のディレクトリ・ファイル情報を収集し runtime.wxsファイル(XMLドキュメント)を生成
    • candleコマンドで、2つのWiX XMLドキュメント(AnalogClock.wxs、runtime.wxs)をコンパイル
    • lightコマンドで、MSI形式インストーラーを生成
  • ランチャー(バッチファイル)にオプション追記

MSIインストーラーのサイズは約38MB、インストール後のサイズは約52MBとなりました。

Java読書会BOF 満20年

今月12月22日(土)に、Java読書会BOF主催の「Effective Java 第3版」を読む会(第1回)を開催しました。

Effective Java 第3版

Effective Java 第3版

Java読書会は、1998年12月にJava互助会の有志でJavaの技術書の読書会を実施したのに端を発し、その後Java読書会BOFとして読書会を毎月1回開催する団体として現在に至るまで活動を続けてきました。

そして、この2018年12月で満20年を迎えました。Java読書会の12月時点での開催データは次の通りです。

項目 データ
通算回数 237回
書籍数 37冊
総ページ数 14,089ページ
平均ページ数 59.4ページ/回
平均参加人数 11.5人/回
最大参加人数 30人
最小参加人数 2人

一つのプログラミング言語で20年間もよく読書会が継続できたものだなぁと思います。オブジェクト指向プログラミングから、言語仕様、仮想マシン、並列処理、ネットワーク、セキュリティ、ユニットテスト、Webアプリケーション、ビッグデータ機械学習Android、リアクティブプログラミング、関数型プログラミングJVM言語のScalaとKotlinなど、Javaが登場してからこの20年間でソフトウェアの世界にもいろいろな技術が登場してきましたが、JavaというOSをまたいだ汎用プログラミング言語がそれら技術と関わりを持ってきたことになります。Javaを積極的に使い勉強してきたことで、幅広くいろいろな技術を学ぶことができたのだと感じています。

2018年は、Javaに大きな変化が訪れた年でもありますが、未来に向けた変化であると思います。来年も、Java読書会BOFは継続して読書会を実施していきますので、よろしくお願いいたします。

Java読書会BOF代表 高橋 徹

JavaFXアプリケーションのJDK 11対応(配布編)

はじめに

JDK 8でのJavaFXアプリケーションは、javapackagerコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめて固めて配布することができました。固め方には、zipアーカイブの他、WindowsLinuxMacOSそれぞれのソフトウェアパッケージ形式(インストーラー)とすることも可能です。

しかし、JDK 11からはJavaFXが分離した際にjavapackagerコマンドも外されてしまいました。OpenJDKでは、javapackagerを代替する新しい機能を開発中*1ですが、早くてJDK 12からとなります。それまでの間、jlinkコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめることとします。なお、jlinkはOS固有のパッケージ形式(インストーラー)を作成することはできません。

jlinkコマンドを使った実行イメージの作成

jlinkコマンドは、指定したモジュールが依存するモジュール群をJDKから抜きだして、実行イメージまとめるのに使います。

モジュール対応したJavaFXアプリケーションの実行イメージの作成

JavaFXアプリケーションが、モジュール対応している場合はjlinkコマンドで簡単に実行イメージを作成することができます。

ただし、モジュールパスでJavaFXライブラリのパスを指定するときは、JavaFX SDKを展開したディレクトリではなく、JavaFX jmodsを展開したディレクトリを指定します。

D:\work\EarthGadget> jlink --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1";dist ^
--add-modules com.torutk.gadget.earth ^
--output runtime ^
--launcher earthgadget=com.torutk.gadget.earth/com.torutk.gadget.earth.EarthGadgetApp
  • --module-pathでは、JDK標準以外のモジュールを収容するディレクトリを指定します。ここでは、JavaFX jmodsファイルのあるディレクトリ(C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1)と、アプリケーションのモジュール化JARファイルのあるディレクトリ(カレントディレクトリ下のdist)を指定しています。
  • --add-modulesでは、アプリケーションのメインモジュール(com.torutk.gadget.earth)を指定しています。
  • --outputでは、実行イメージを生成するディレクトリを指定しています。
  • --launcherでは、実行イメージの中にアプリケーション起動用のコマンド(シェルスクリプト/バッチファイル)の名前と起動するモジュールおよびメインクラス名を指定しています。

実行イメージが展開されるディレクトリに、JavaFX関係のライブラリ(ネイティブライブラリのdllファイル、クラスライブラリのJARファイル等)も展開されます。

outputオプションで指定したruntimeディレクトリ下のbinディレクトリには、launcherオプションで指定した起動スクリプトファイル(earthgadget)/起動バッチファイル(earthgadget.bat)があるので、UNIX系OSなら前者を、Windows OSなら後者を実行するとJavaFXアプリケーションが立ち上がります。

jlinkコマンドのmodule-pathオプションで、JavaFXSDKのlibディレクトリを指定すると、実行イメージの中にネイティブライブラリが含まれないので実行時にエラーとなってしまいます。jlinkコマンドでJavaFXを指定する場合は、JavaFXのjmodsを指定します。

モジュール対応していないJavaFXアプリケーションの実行イメージ作成(改訂)

JavaFXアプリケーションがモジュール対応していない場合は、JavaFXアプリケーションが必要とするモジュールをjdepsコマンドでリストアップしてからjlinkコマンドでリストアップされたモジュールをそれぞれ指定します。

ただし現時点ではJDKのモジュールから必要なものを抜粋した実行イメージを生成することができますが、実行イメージにJavaFXライブラリとアプリケーションを含めることはできませんでした。

jdepsでアプリケーションの実行に必要なモジュールを調べる

まず、アプリケーションJARファイル(非モジュール対応)をjdepsで解析します。

ここで、非モジュールJARの依存関係を解析する場合、jdepsコマンドのオプション--print-module-depsおよび--list-depsは使用しないのがミソです(id:skrbさんの次のブログ参照)。

skrb.hatenablog.com

まずは、アプリケーションJARファイルだけを指定した場合の実行例です。

D:\work\EarthGadget> jdeps -s dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> 見つかりません

D:\work\EarthGadget>

アプリケーションJARが依存するJDKのモジュールのみ表示されます。JavaFXのモジュールはリストされません。また、JavaFXライブラリが必要とするJDKのモジュールもリストされていません。

そこで、JavaFXライブラリを解析対象に追加します。

D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> javafx.base
EarthGadget.jar -> javafx.controls
EarthGadget.jar -> javafx.graphics
EarthGadget.jar -> 見つかりません
javafx.base -> java.base
javafx.base -> java.desktop
javafx.controls -> java.base
javafx.controls -> javafx.base
javafx.controls -> javafx.graphics
javafx.fxml -> java.base
javafx.fxml -> java.scripting
javafx.fxml -> java.xml
javafx.fxml -> javafx.base
javafx.fxml -> javafx.graphics
javafx.graphics -> java.base
javafx.graphics -> java.desktop
javafx.graphics -> java.xml
javafx.graphics -> javafx.base
javafx.graphics -> jdk.unsupported
javafx.media -> JDK removed internal API
javafx.media -> java.base
javafx.media -> javafx.base
javafx.media -> javafx.graphics
javafx.swing -> java.base
javafx.swing -> java.datatransfer
javafx.swing -> java.desktop
javafx.swing -> javafx.base
javafx.swing -> javafx.graphics
javafx.swing -> jdk.unsupported.desktop
javafx.swt -> java.base
javafx.swt -> javafx.base
javafx.swt -> javafx.graphics
javafx.swt -> 見つかりません
javafx.web -> java.base
javafx.web -> java.desktop
javafx.web -> java.xml
javafx.web -> javafx.base
javafx.web -> javafx.controls
javafx.web -> javafx.graphics
javafx.web -> javafx.media
javafx.web -> jdk.jsobject
javafx.web -> jdk.xml.dom

なお、--module-pathに、JavaFXSDKではなく、JMODの方を指定すると何故か依存が解析されませんでした。

D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\javafx\javafx-jmods-11.0.1" dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> 見つかりません

D:\work\EarthGadget> 

非モジュール対応アプリケーションJARファイル(EarthGadget.jar)が依存しているのは

となります。よって、jlink でこれらを指定すればあとは依存関係を辿って必要なモジュールが取り込まれた実行イメージが生成されます。なお、java.baseは暗黙で使用されるモジュールなので指定を省略できます。javafx.graphicsはjavafx.controlsが依存しているのでこちらも省略できます。javafx.baseはjavafx.controlsが依存しているのでこちらも省略できます。

jlinkで非モジュール対応アプリケーションJARのための実行イメージを生成する
D:\work\EarthGadget> jlink --add-modules javafx.controls,java.prefs ^
 --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1" ^
 --output runtime

生成された runtime ディレクトリの容量は約87MBとなりました。
JavaFXライブラリ(クラスライブラリおよびネイティブライブラリ)も含まれています。
なお、アプリケーションはこのruntimeには含まれません。

jlinkで作成した実行イメージを使ってアプリケーションを実行する
D:\work\EarthGadget> runtime\bin\java -jar dist\EarthGadget.jar

まとめ

  • モジュール対応したJavaFXアプリケーションは、jlinkコマンドで実行に必要なJDK、ライブラリ(Javaクラスライブラリ、ネイティブライブラリ)、アプリケーションをまとめたアプリケーション実行イメージを生成できる。
  • モジュールに対応していないJavaFXアプリケーションは、jdepsコマンドで実行に必要なJDKのモジュールを解析し、続いてjlinkコマンドで必要なモジュールを抜粋し実行イメージを生成する。ただし、非モジュール対応のJARファイルは実行イメージには取り込まれない。

*1:JEP 343: Packaging Tool

JavaFXアプリケーションのJDK 11対応(NetBeans編)(モジュール対応編)

はじめに

じゃばえふえっくす Advent Calendar 2018 - Qiita20日目のエントリです。

前回のブログ(JavaFXアプリケーションのJDK 11対応(NetBeans編) - torutkのブログ)では、アプリケーションをJava SE 9から導入されたモジュールシステム(Java Platform Module System、以下JPMSと呼ぶ)には対応せずに、JavaFXライブラリをクラスパスで参照する方法でJDK 11に対応させました。

しかしながら、JPMS対応をしなかったため、実行時に--add-modulesを指定するか、メインクラス(javaランチャーから最初に指定するクラス)のロード時にJavaFXのクラスを参照しないようにする(javafx.application.Applicationの継承をやめる)必要があります。

そこで、今回のエントリではJPMS対応によるJDK 11対応をすることにします。

JPMS対応することで、上述の制約がなくなります。さらに、Java実行環境と一緒にアプリケーションを配布する際に、Java実行環境をアプリケーションに必要なモジュールに限定することで配布サイズ削減が図れます。jlinkコマンドでアプリケーションとアプリケーション実行に必要とするモジュールだけを1か所にまとめた実行イメージを作成できます*1

対応方法

プロジェクトの作成

NetBeans 10で[File]メニュー > [New Project...] で、カテゴリ[Java]から[Java Modular Project]を選択します。

f:id:torutk:20181209000836p:plain
NetBeans 10 New Project Java Modular Project

プロジェクト名とプロジェクトを作成するフォルダを指定します。

f:id:torutk:20181209001657p:plain
NetBeans 10 New Project Java Modular Project で プロジェクト名と場所を指定

Java Modular Projectで生成したプロジェクトでは、プロジェクトの下に複数のモジュールが定義できるマルチモジュールな構成となります。よって、プロジェクト作成後に、少なくとも1つのモジュールを定義します。

プロジェクトペインで今作成したプロジェクトを右クリックし、[New] > [Module]を選択します。

f:id:torutk:20181209002117p:plain
NetBeans 10 Java Modular Project に新しいモジュールを指定

モジュール名を指定します。モジュール名は、一般的にはモジュールに含むパッケージ名のうち代表的なものとします。

f:id:torutk:20181209002535p:plain
NetBeans 10 Project に新しいモジュールを指定

モジュールを作成すると、プロジェクトの配下にモジュールが追加され、その中にmodule-info.javaが生成されます。

f:id:torutk:20181209002845p:plain
NetBeans 10 Project に追加された新しいモジュール

JavaFXモジュールのパスを指定

プロジェクトのプロパティを開き、左側ペインで[Libraries]を選択、右側ペインの[Compile]タブで、Modulepath の右端の[+]をクリックします。ポップアップメニューが出るので、[Add Library」を選択、ライブラリ一覧からJavaFX 11を選択します(NetBeansのライブラリにJavaFX 11を追加する方法は、JavaFXのNetBeans設定 - ソフトウェアエンジニアリング - Torutk参照)。

f:id:torutk:20181209004431p:plain
NetBeans 10 Project のモジュールパスにJavaFX 11を指定

ソースファイルの移動

NetBeans 8.2/JDK 8で作成したJavaFXアプリケーションのソースファイルを、新しく作成した Java Modular Projectのプロジェクトへ移動します。NetBeans 10で旧プロジェクトを開き、ソースファイルを含むパッケージをマウスでドラッグし、新プロジェクトのモジュールの下の[classes]にドロップします。

f:id:torutk:20181219072428p:plain
旧プロジェクトから新プロジェクトへのソースファイル移動

そのままドロップするとフォルダが移動になるので、コピーするにはCtrlキーを押しながらドロップします。

module-info.javaの定義

プロジェクトのライブラリ定義のモジュールパスにJavaFX 11ライブラリを指定しただけでは、アプリケーションからJavaFXのクラスを参照することはできません。JavaFXライブラリのクラスを参照するimport文がエラーになってしまいます。

f:id:torutk:20181209005220p:plain
NetBeans 10 Project のモジュールパスにJavaFX 11を指定しただけでは参照を解決できず

そこで、プロジェクトのモジュールパスにJavaFXライブラリを指定した後、module-info.javaに使いたいクラスが含まれるモジュールを定義します。

module com.torutk.gadget.image {
    requires javafx.controls;
    requires javafx.fxml;
    opens com.torutk.gadget.image to javafx.graphics, javafx.fxml;
}
  • 基本はjavafx.controls モジュールへの依存を記述。javafx.controlsからjavafx.graphicsモジュールへの依存の推移により暗黙的な依存が定義されるので、javafx.graphicsへの依存は記述不要。
  • FXMLを使う場合は、javafx.fxmlモジュールへの依存を記述。
  • アプリケーションのメインクラス(javafx.application.Applicationクラスを継承するアプリケーションクラス)を持つパッケージ名をopensで記述。

ビルド成果物

プロジェクトの下に定義したモジュール毎に、ビルド成果物であるモジュールファイル(JARファイル)が生成されます。

f:id:torutk:20181220061707p:plain
ビルド成果物

JARファイルの内容が次です。モジュール記述子(module-info.class)が含まれています。

f:id:torutk:20181220071325p:plain
モジュールファイル(JAR)の内容

コマンドラインからの実行

NetBeans上でビルドしたJARファイルをコマンドラインから実行するには、少々長いオプションを指定します。

D:\work\ImageGadget> java --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib";dist -m com.torutk.gadget.image/com.torutk.gadget.image.ImageGadgetApp
  • JavaFX 11ライブラリは、C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1 にインストール
  • アプリケーションのモジュールJARファイルは、カレントディレクトリのdist下にある

NetBeans上でメインクラスの指定をJARマニフェストにする方法が見つからなかったのでオプションが長くなってしまいました。

まとめ

  • アプリケーションをJPMS対応するには、NetBeansのプロジェクト種類でJava Modular Projectを選ぶ
  • Java Modular Projectで生成したプロジェクトでは、最低1つはモジュールを作成する
  • JDK標準以外のライブラリを利用するときは、プロジェクトのプロパティでライブラリをモジュールパスに登録する(クラスパスではなく)
  • java.baseモジュールに含まれるクラス以外を利用するときは、モジュール定義(module-info.java)に依存を記述する

*1:@skrbさんのコメントをもとに文章を修正しました。モジュール対応・非モジュール対応のアプリケーションの実行イメージの作成については、 JavaFXアプリケーションのJDK 11対応(配布編) - torutkのブログ に書きました。

JavaFXアプリケーションのJDK 11対応(NetBeans編)

はじめに

これまでにNetBeans 8.2/JDK 8のAntプロジェクト(種類はJavaFXアプリケーション)で作成したJavaFXアプリケーションを、JDK 11に対応させようと試みました。

NetBeans は間もなくリリース予定のNetBeans 10のテストバージョン(vc4)で、OpenJDK 11.0.1とJavaFX 11.0.1を使います。

 今回はアプリケーション側のモジュール対応は行いません。移行後に段階的にモジュール対応を進めます。

最初の試み

まずは、JDK 11からJavaFXが分離したのに伴い、JavaFX 11を別途インストールしマシン上に展開、NetBeansのプロジェクト設定でライブラリとしてこのJavaFXを指定する方針で進めました。

 

JavaFX 11.0.1をダウンロードし、NetBeansのライブラリ定義に加え、既存のJavaFXアプリケーションのプロジェクトにクラスパスとして追加します。

コンパイルは通りますが、実行すると

JavaFX deployment library not found in active JDK.
Please check that the JDK is correctly installed and its version is at least 7u4 on Mac or 7u6 on other systems.

とエラーになってしまいます。NetBeansのビルド定義には、JDKの中にあるJavaFXライブラリの場所を探すコードがあり、見つからないと上述のようにエラーとなってしまいます。

この問題を解決するには、NetBeansが生成したビルド定義に大分手を入れる必要があります。この試みは挫折とします。

次の試み

次は、NetBeansでプロジェクトを新規に作り直す方法で進めます。

既存のディレクトリにNetBeansで新規プロジェクトを作成するとエラーになるので、新しいディレクトリにプロジェクトを作成します。

プロジェクト種類をJavaFXアプリケーションで新規作成しようとするとエラー

このとき、プロジェクトの種類をJavaFXアプリケーションとすると、

Failed to automatically set-up a JavaFX Platform.
Please go to Platform Manager, create a non-default Java SE platform, then go to the JavaFX tab,
enable JavaFX and fill in the paths to valid JavaFX SDK and JavaFX Runtime.

とエラーになります。

プロジェクト種類をJavaアプリケーションで新規作成するとビルドはOKだが実行エラー

そこで、プロジェクト種類をJavaアプリケーションとして新規作成します。そこに既存のソースコードを追加し、ライブラリにJavaFX 11を追加します。

これでビルドは成功しますが、アプリケーションを実行するとエラーとなってしまいます。

エラー: JavaFXランタイム・コンポーネントが不足しており、このアプリケーションの実行に必要です

--add-modulesでJavaFXモジュールを指定して実行エラー回避

解決方法は、javaの実行時のJVMオプションで、--add-modules=javafx.controls のようにアプリケーションから利用するJavaFXのモジュールを指定します。FXMLを使うアプリケーションの場合は、--add-modules=javafx.controls,javafx.fxml のように指定します。

Getting Started with JavaFX 11

なぜ--add-modulesでJavaFXモジュールを指定しなければならないか

ですが、なぜJavaFXのライブラリ(JARファイル)をクラスパスで指定しているのにエラーとなってしまうのか不思議でした。

いろいろ調べてみたところ、次のメーリングリストでその原因が言及されていました。

launching JavaFX in 11

これによると、実行時のエラーはjavaコマンドが最初に参照するメインクラスがJavaFXのApplicationクラスを継承している場合に発生します。javaコマンドがメインクラスをロードする際に、メインクラスが継承しているスーパークラスもロードする必要があります。しかしJavaFXのApplicationクラスがスーパークラスの場合、javafx.graphicsモジュールを探しに行って存在しない場合、クラスパスを探すことなくエラーとなります。

Mainクラスでjavafx.application.Applicationクラスの継承をやめる

試しに、メインクラスでJavaFXのApplicationクラスを継承するのをやめて、mainメソッドの中でJavaFXのApplicationを継承する別クラスを初期化するコードを呼ぶように修正したところ、--add-modulesの指定をせずに実行できるようになりました。

まとめ

  •  NetBeansJavaFXアプリケーション・プロジェクトは、JavaFXが分離したJDKOracle JDK 11以降およびOpenJDK)には対応できない
  • NetBeansJavaアプリケーション・プロジェクトでJavaFXアプリケーションをビルドする際は、JavaFX 11を別途ダウンロードしマシン上に配置し、NetBeansのライブラリ定義を追加し、プロジェクトからJavaFXライブラリを参照する(クラスパスとして参照)
  • NetBeansJavaアプリケーション・プロジェクトでJavaFXアプリケーションを実行する際は、メインクラスにJavaFXのApplicationクラスを継承させず、別クラスで継承し、メインクラスのmainメソッドにはその別クラスを初期化するコードを記述する。

 

JDK 11の環境設定

JDK 11から、Oracleが提供するWindows OS向けのJDKは、Oracle JDKとOpenJDKの2種類になりました。

Oracle JDK 11は、有償で技術サポートが含まれ、LTS(長期サポート版)となる商用製品となりました。なお、開発・試験・デモ用など使用用途に制限のあるOTNライセンスでの無償提供もあります。
一方、OpenJDK 11は、無償で提供されています。

Oracle JDKもそのソースコードはOpenJDKとして開発されています。従来はOpenJDKのソースには含まれないOracle JDK独自機能(Java Flight Recorder、Application Class Data Sharing、フォント描画等)がいくつかありましたが、JDK 11に向けてOpenJDKに統合されてきています。このOpenJDKのソースはGPLであり、OpenJDKのソースをビルドしてバイナリを提供する団体がいくつか登場しています。

JDKの入手先

Oracle JDK 11

商用利用するアプリケーションをこのOracle JDKで動かす場合には、有償のライセンス契約が必要となります。開発・試験・デモ用など使用用途に制限のあるOTNライセンスは無償で提供されています。

Java SE - Downloads | Oracle Technology Network | Oracle

OpenJDK 11 Oracleビルド版

先のOracle JDK 11とは別に、OracleがOpenJDKソースをビルドしてバイナリを提供しています。
GPLv2 のクラスパス例外付きライセンスで提供されています(無償)。

JDK 11.0.1 GA Release

Zulu

Azul Systems社がOpenJDKを独自にビルドしバイナリを提供しています。Zuluの利用は無償で、技術サポートを有償で提供しています。

Download OpenJDK Java Linux Windows macOS Alpine Java 11 Java 8

AdoptOpenJDK

ロンドンJavaコミュニティが運営し、OpenJDKコミュニティの幅広いメンバーの活動によってOpenJDKをビルド・提供する団体です。

AdoptOpenJDK - Open source, prebuilt OpenJDK binaries

Windows上でのOracle JDKの環境設定バッチ

Oracle JDKインストーラーでインストールし、レジストリにインストール場所が記録されます。これまでは、レジストリからJDKの場所を調べて環境変数を設定するバッチファイルを作って環境設定をしていました。

Setting oracle jdk path using registory for Windows command prompt - Gist

OpenJDKは、zipで提供、インストールしたい場所に展開するだけのインストールなので、レジストリからOpenJDKの場所を調べることができません。そこで、自分で決めたインストールディレクトリの下にJDK-<バージョン番号>のディレクトリを探してそれを環境変数に設定するようにしました。

LTSについて

これまで、JDKは1年半〜4年半の間隔でメジャーバージョンアップをしてきました。また、マイナーバージョンアップにおいても、セキュリティアップデート、バグ修正のほか機能追加が行われたりしていました。

これからは、LTS版はセキュリティアップデートとバグ修正が続き、機能追加は半年毎にバージョンアップされるOpenJDKの方で行われるようになります。なので、JDK 12、13、14、15、16と半年毎にリリースされている間、LTS版のJDK 11はセキュリティパッチとバグ修正パッチが順次提供されます。

なので、ミッションクリティカルなシステムではこのLTS版を使うと、より頑健になります。

ミッションクリティカルでなく、これまで3ヶ月毎にリリースされるCPU(Critical Patch Updte)やPSU(Patch Set Update)のJDKに更新していない、リリース時点のJDKバージョンで固定して使っているシステムでは、OpenJDKで十分でしょう*1

また、LinuxディストリビューションにはこれまでもOpenJDKが含まれていたので、こちらを使っていたシステムはそのままLinuxディストリビューションのOpenJDKを使い続けることになると思います。

*1:3ヶ月毎にJDKをアップデートして回帰テストなんてやってられないや、というシステムなど

Wix toolset 3.11のインストールで.NET 3.5を要求される

自宅PCのインストールソフトウェアを整理していて、Wix toolset(ちょっと古いバージョン)をアンインストールして最新の3.11.1をインストールしようとしたところ、.NET Framework 3.5が必要とインストーラーがエラー停止しました。
Windows 10では、.NET Framework 4.6(Creator Updateで4.7)が入っていますが、これではダメで古い .NET Framework 3.5がないと先に進めません。

コントロールパネルの[プログラム]>[プログラムと機能]>[Windowsの機能の有効化または無効化]から.NET Framework 3.5にチェックを付けてインストールする手順で対処可能なようです。

Wix 3.14(3系の次のリリース予定)またはWix 4において、.NET Framework 3.5への依存が解消されるそうですが、まだどちらもリリースはされていません。

インターネット非接続環境での.NET 3.5のインストール

Windows 10にインターネット非接続な環境で.NET Framework 3.5をインストールする方法を調べてみたら、Windows 10のインストールメディアを必要とします。

.NET Framework 3.5 を有効化する手順について ( Windows 10 ) | Ask CORE

うーん、プレインストールのノートPCではWindows 10のインストールメディアはないし、インターネット接続環境した別マシンでWindows 10のインストールメディアを作成し、外付けドライブに置いてそれを持ってくるとかとっても面倒です。

なお、アプリケーション実行用のランタイムイメージは.NET Framework 3.5については用意されていないようですね。ということは、.NET Framework 3.5以下で作成したアプリをWindows 10で使うのはかなり難関(不可能ではないが)です。