RECENT POSTS

Jigsaw のお勉強 その4 JavaFX (Spinner がほんの少しだけ良くなった)

Java JavaFX

このエントリーは じゃばえふえっくす Advent Calendar 2018 の初日(12月4日)です。

未だにJigsawのお勉強をしています。(^_^;)

今回はJavaFXを使ってみます。

そんなJavaFXですが正式リリース前からさらにリリースされてからもいろいろありました。

現在はJavaにバンドルされていません。

正確にはいろいろなところからJDKが提供されているのでひょっとしたらJavaFXをバンドルしたJavaがあるのかもしれません。

今回はOpenJDKとOpenJFXを使います。

JavaFX 11でjavafx.scene.control.Spinner<T>クラスにほんの少し優しい変更が追加されたのでそれを試してみました。

矢印ボタンをマウスにて押し続けたときの入力時間がJavaFX 8の750ms固定だったのが自由に変更できるようになりました。

InitialDelayとRepeatDelayが設定可能となります。

デフォルトの設定時間はそれぞれ300ms、60ms となっています。

まず、Spinnerについて少しだけ復習しておきましょう。

SpinnerのAPIドキュメントに下記のように書かれています。

順序付けられたシーケンスからユーザーが数値またはオブジェクト値を選択できるようにする単一行のテキスト・フィールド。

通常、スピナーはシーケンスの要素間を移動するための小さな矢印ボタンのペアを提供します。

キーボードの上/下矢印キーでも要素間を自由に移動できます。

ユーザーがスピナーに直接(有効な)値を入力することもできます。

コンボ・ボックスも同様の機能を提供しますが、スピナーの方が好まれる場合があるのは、重要なデータを不明瞭化する可能性があるドロップ・ダウン・リストが不要であり、また、他の多くのJavaFX UIコントロールのようにObservableListデータ・モデルを使用せずに、wrappingなどの機能や、より単純な’無限’データ・モデルの仕様(SpinnerValueFactory)を使用できるためです。

Spinnerのシーケンス値はSpinnerValueFactoryで定義します。

value factoryはコンストラクタ引数として指定し、value factory propertyを使用して変更できます。

JavaFXには、次に示す一般的なタイプのSpinnerValueFactoryクラスが用意されています。

•SpinnerValueFactory.IntegerSpinnerValueFactory

•SpinnerValueFactory.DoubleSpinnerValueFactory

•SpinnerValueFactory.ListSpinnerValueFactory

Spinnerには、Spinnerの現在のvalueの表示および変更を行う、editorと呼ばれるTextField子コンポーネントがあります。

Spinnerはデフォルトで編集不可能ですが、editable propertyをtrueに設定すると、入力を受け入れることができます。

Spinnerエディタは、値ファクトリのvalue propertyに対する変更をリスニングすることにより、値ファクトリとの同期を保ちます。 ユーザーがeditorに表示された値を変更した場合、Spinnerのvalueとeditorの値が異なってしまう可能性があります。

モデルの値をeditorの値と同じにするには、ユーザーが[Enter]キーを使用して編集をコミットする必要があります。

APIドキュメントによると一般的なタイプのSpinnerValueFactoryクラスと使ってSpinnerインスタンスを作成できると書かれていました。

Spinner​(double min, double max, double initialValue) // SpinnerValueFactory.DoubleSpinnerValueFactory

Spinner​(double min, double max, double initialValue, double amountToStepBy) // SpinnerValueFactory.DoubleSpinnerValueFactory

Spinner​(int min, int max, int initialValue) // SpinnerValueFactory.IntegerSpinnerValueFactory

Spinner​(int min, int max, int initialValue, int amountToStepBy) // SpinnerValueFactory.IntegerSpinnerValueFactory

Spinner​(ObservableList<T> items) // SpinnerValueFactory.ListSpinnerValueFactory

Spinner​(SpinnerValueFactory<T> valueFactory) // 指定されたvalue factoryを設定する場合

Spinnerインスタンスを作成するのは容易にできることが確認できたので次はSpinnerの定数フィールド値を使ってスタイルの設定方法を調べてみます。

public static final String STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL

水平方向(左向きと右向き)の矢印がSpinnerの左側に配置されます。

public static final String STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL

垂直方向(上向きと下向き)の矢印がSpinnerの左側に配置されます。

public static final String STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL

水平方向(左向きと右向き)の矢印がSpinnerの右側に配置されます。

public static final String STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL

Spinnerの左側に減分矢印、右側に増分矢印が配置されます。

public static final String STYLE_CLASS_SPLIT_ARROWS_VERTICAL

スピナーの幅全体にわたって上下に伸びた矢印が配置されます。

何も指定をしない場合はデフォルトの垂直方向(上向きと下向き)の矢印がSpinnerの右側に配置されます。

Spinnerインスタンスの作成、スタイルの設定方法が解ったので試してみます。

Spinnerのデザインをデフォルトの垂直方向(上向きと下向き)の矢印がSpinnerの右側に配置

1

Spinnerのデザインを水平方向(左向きと右向き)の矢印がSpinnerの左側に配置
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL);

2

Spinner のデザインを垂直方向(上向きと下向き)の矢印がSpinnerの左側に配置
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL);

3

Spinnerのデザインを水平方向(左向きと右向き)の矢印がSpinnerの右側に配置
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL);

4

Spinnerのデザインを左側に減分矢印、右側に増分矢印が配置
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);

5

Spinnerのデザインをスピナーの幅全体にわたって上下に伸びた矢印が配置
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL);

6

// 最小値 0、最大値 100、初期値 50、増分または減分するステップの量のSpinnerインスタンス作成
Spinner<Integer> spinner = new Spinner<>(0, 100, 50, 10);

javafx.​scene.​Nodeパッケージのpublic final ObservableList<String> getStyleClass()でノードを論理的にグループ化するために使用できる文字列識別子のリストを取得しava.​util.​Listパッケージのpublic abstract boolean add(E arg0)メソッドでSpinnerの定数フィールド値を追加して設定します。

Spinnerの増分、減分の矢印ボタンの配置デザインの設定はこれで可能となりました。

次に Spinnerに表示されている値のアライメントとカスタムフォントを設定してみます。

//  カスタムフォント、アライメントを設定
Font f = Font.loadFont(this.getClass().getResourceAsStream(“resources/AKUBIN1.34.ttf”), 28);
spinner.getEditor().setStyle(“-fx-text-fill: black; -fx-font: 18px ‘Akubin’; -fx-alignment: CENTER_RIGHT;”);

SpinnerExample

上の行でカスタムフォントを読み込んでその下の行でSpinnerにそのフォントを設定、テキストのサイズ、文字色、アライメントを設定しています。

そしてついでに

// Spinneのエディタをユーザー入力可能とする
spinner.setEditable(true);

としてユーザー入力可能としてます。

増分、減分のステップ量は変わらずユーザーによって入力された値からの増分値、減分値となります。

また、最大値、最小値を超えることはありません。

ここまでのプログラムのソースコードは次のようになります。

それではSpinnerにInitialDelayとRepeatDelayを設定するプログラムを組んでみます。

せっかくだからJDK 12 Early-Access Builds (build: 21)とJavaFX Early-Access Builds (openjfx-12-ea+2)を使ってみます。

さらに、モジュラjarを作ってモジュール化します。

そして、jlinkで配布用にカスタムJREをバンドルしたアプリケーションを作成します。

NetBeans IDE 10.0-vc4を使ってお気楽に組もうとしたがこのバージョンには未対応なので古典的なツールを使いました。

ちなみにNetBeans IDE 10.0 Devでプロジェクトをビルドし、jlinkでカスタムJRE組み込みアプリケーションの作成はできました。

ただ、エラーバッジの嵐のエディタは心が痛みます。

それではお気に入りのエディタか心を痛めながらNetBeans IDE 10.0-vc4を使って下記ファイルを作成します。

 

 

 

 

プロジェクトの構成は下図のようにします。

11

カスタムフォントを使うのでお気に入りのフォントをご用意ください。

コンパイル時にはJDK 12の新機能を使えるように–release 12 –enable-preview VMオプションをつけます。

Java SE 11からJavaFXはバンドルされなくなったのでそれらライブラリをダウンロードしてコンパイル、実行時にモジュールパスを指定します。

JavaFXはこちらから入手できます。

https://gluonhq.com/products/javafx/

JavaFX Linux SDKとJavaFX Linux jmodsがあります。

JavaFX Linux SDKだけでいいのですがjlinkで配布用にカスタムJREをバンドルしたアプリケーションを作成する場合はJavaFX Linux jmodsが必要となります。

-d オプションでbin/IncludeeJavaFXディレクトリにコンパイルによって作成されるクラスファイルが格納されるようにしています。

–module-pathオプションでJavaFX SDKのパスを指定します。

–add-modulesオプションでアプリケーションで必要とされるモジュールを指定します。

12

FXMLDocument.fxmlはコンパイルを実行しても出力ディレクトリbin/IncludeeJavaFXには移動、コピーされないので存在しません。

FXMLDocument.fxmlをコンパイルして作成されたクラスファイルのある場所にコピーします。

13

フォントを格納しているresourcesディレクトリもコピーします。

14

プロジェクトの構成は下図のようになります。

15

それでは実行してみましょう。

–enable-preview VMオプションを忘れずに。

–module-path、–add-modules、–moduleオプションも必要です。

16

ちゃんとコンパイルされて実行できました。

17

と、思いきや

18

何やら妙な警告がでました。(>_<。)

GTK libraries version 3を使うとだめそうなので-Djdk.gtk.verbose=true -Djdk.gtk.version=2とVM オプションをあたえます。

19

これってJavaFX 12のリリースまでには修正されるのかな?

20

それではこのプログラムをモジュラjar化してみます。

modsディレクトリを作成してそこにモジュラjarを格納します。

–module-versionでこのモジュールのバージョンを設定します。

実行時メインクラスの指定をしなくていいように–main-classオプションを使ってメインクラスを指定してアプリケーションエントリポイントを設定します。

21

モジュラjarがちゃんとできたか確認します。

22

問題無さそうなのでプログラムを走らせてみます。

–module-pathにはこのアプリケーションを格納しているmodsディレクトリとJavaFX SDKのパスを指定します。

–moduleオプションはメインクラスの指定を省力できるようにしたのでモジュール名だけで実行できます。

モジュラjar作成時にメインクラスの指定をしなかった場合は–module モジュール名/モジュールのメインクラス名とアプリケーションエントリポイント指定しなければいけません。

今回の場合だと、–module IncludedJavaFX/jp.yucchi.includedjavafx.IncludedJavaFXとします。

23

アプリケーションのモジュール化に成功し、ちゃんと動くことが確認できました。

24

最後にjlinkで配布用にカスタムJREをバンドルしたアプリケーションを作成します。

includedjavafx-imageディレクトリを作成しそこに成果物を格納します。

–module-pathオプションでJDKとJavaFXのモジュールを指定します。JavaFX Linux SDKのパスじゃなくてJavaFX Linux jmodsのパスを指定することに注意してください。

–add-modulesオプションでこのアプリケーション自体を指定します。

–launcherオプションを次のように設定します。

–launcher <コマンド名>=<モジュール名><メインクラス>

–outputオプションで出力先を設定します。

25

jlinkによって作成されたランチャーファイルにVMオプションを記述します。

26

27

これを忘れると少し焦ります。(^_^;)

28

動きましたね。

JavaがインストールされてないPCでも動くことを確認しました。(Linux)

ただしWindowsでは動きません。

Windowsで動く配布用アプリはWindowsで作成しなくてはいけないようです。

Write once, run anywhere ってのは遠い過去の夢になってしまったのでしょうか・・・

Spinner

肝心のことを忘れていました。

上のGifアニメで増分、減分ボタンを押しっぱなしにしている時のSpinnerの更新時間に注目してください。

// タイマーの時間を設定
versionSpinner.setInitialDelay(Duration.millis(INTIAL_DELAY_TIME));
versionSpinner.setRepeatDelay(Duration.millis(REPEAT_DELAY_TIME));

setInitialDelay​(Duration value) メソッドで押し続けて最初に更新される時間を設定しています。

このプログラムでは解りやすくするために1500ミリ秒に設定しました。

そのまま押し続けた時の更新時間(リピート時間)は

setRepeatDelay​(Duration value) メソッドで 500ミリ秒と設定しました。

Java SE 8 u40 では750ミリ秒に固定されていて変更することができなかったので少しうれしいアップデートです。

Swingも悪くはないけど近い将来にはJavaの標準 GUI はJavaFXになってほしい。

 

Jigsawにもほんの少しだけ慣れてきたけど難しいですね。

モジュールの依存関係を調べるのがお手軽にできるツールがあればいいのだけど・・・

jdepsは万能ではないので落とし穴に落ちます。(>_<。)

今回のプログラムではFXMLを利用しています。

JavaFXでGUIの構築にはとても便利です。

で、それを使うためにmodule-info.javaにrequires javafx.fxml;とrequiresモジュールディレクティブ設定します。

ところがそれだけではjava.lang.reflect.InvocationTargetExceptionが投げられます。

FXMLを利用したJavaFXアプリケーションではjavafx.fxmlモジュール側からこのプログラムのFXMLのコントローラークラスに対してリフレクションによるアクセスがあります。

モジュールのカプセル化はリフレクションにも適用されるからです。

JDK 9より前はリフレクションを使えばパッケージ内の全てのクラスやクラスの全てのメンバーにアクセスできました。

つまりリフレクションは開発者の本意と関係なくカプセル化を破壊することが可能です。

Jigsawでは強力で繊細なカプセル化が提供されています。

デフォルトでは外部モジュールからモジュール内のクラスにアクセスすることはできません。

外部モジュールからアクセスできるのはexportsされたパッケージの公開クラス、公開メンバだけなのです。

非公開なメンバへのアクセスは外部モジュールから禁止されています。

こういった所でもモジュール化のメリットである依存性、公開範囲の制限が絡んでくるんですね。

なのでこのリフレクションによるjavafx.fxmlモジュール側からのアクセスを許可する必要があります。

それにはopens…toモジュール・ディレクティブを設定します。

module-info.javaにopens jp.yucchi.includedjavafx to javafx.fxml;とopensモジュールディレクティブを付け加えるだけです。

module-info.javaにこのモジュールディレクティブを加えることによって実行時にのみ特定のモジュールに対してパッケージへのアクセスを許可することが可能です。

つまり、特定のパッケージ内のpublic型(およびネストされているpublic型とprotected型)に対して実行時にのみアクセスできることを指定可能となります。

指定したパッケージのすべての型(およびその型のすべてのメンバ)にリフレクションを使ってアクセスすることもできます。

Jigsawの強力で繊細なカプセル化はJDK 9より前のものより開発者には喜ばれるはずですね。

そうなるとjdepsのような依存性を解決する強力なツールの必要性が求められます。

そのうち統合開発環境なんかに乗っかってくることを期待します。

 

Jigsaw のお勉強 その1

Jigsaw のお勉強 その2

Jigsaw のお勉強 その3

Hatena タグ: ,


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Jigsaw のお勉強 その3

Java

Jigsaw のお勉強の続きです。

超スローペースですがゆっくり慌てず三歩進んで二歩下がるような感じでもう暫く進めていこうと思っています。

今回は、最新Java情報局 「Java SE 9を先取り、Project Jigsawでモジュールを作成する」の写経をおこなってみました。

プログラムは同じではないのですがProject Jigsawで実現される機能の確認は同様にしました。

元記事で解説されているようにモジュールの定義は次のようになっています。

モジュールは複数のパッケージやリソースなどを含む、自己記述可能なコードの集合

今までの JARファイルにモジュール名が付いて依存性や公開範囲を記述できるようになったようです。

詳しくは元記事を参照してくださいませ。

では、モジュールを作っていきます。

プログラムを起動したら挨拶(文字列)を表示させるだけのプログラムです。

挨拶を表示させるためのインタフェースとしてGreetingインタフェース、その実装クラスとしてMultilingualGreetingクラスを作成します。

実装クラスのMultilingualGreetingクラスは日本語の挨拶か英語の挨拶をランダムに返します。

MultilingualGreetingクラスは外部からアクセスされることを避けるようにします。(Java SE 9 からインターフェイスにprivateメソッドが記述できるようになったのは今回は忘れてください。)

このアプリケーションをモジュールとするためにmodule-info.javaをトップディレクトリに作成します。

exports jp.yucchi.greeting;とmodule-info.javaに記述されています。

これは公開範囲を定義しています。

jp.yucchi.greeting.internalパッケージは公開されてないので外部からアクセスすることはできません。

それではjp.yucchi.greetingモジュールを使用するモジュールを作成します。

続いてこちらもモジュールとするためにmodule-info.javaを作成します。

先程作成したjp.yucchi.greetingモジュールを使用するためにrequires jp.yucchi.greeting;と記述しています。

これは依存性の定義となります。

面白いのはexports jp.yucchi.helloと自分自身を公開すると定義しています。

Helloクラスのmain()メソッドをコールすることも外部アクセスとなるからです。

これでシンプルなお試しプログラムが完成しました。

ディレクトリ構造は前回までと少し変更しています。

1

それぞれコンパイルしてみましょう。

binディレクトリを作成してコンパイルされたファイルを配置しました。

2

それでは確認のためにプログラムを実行してみます。

3

ちゃんとうごきましたね!(^_^)

それではモジュラーJARとしてパッケージ化してみましょう。

modsディレクトリを作成してモジュラーJARとしてパッケージングし配置しました。

4

一応できているみたいですが正しくできているか念の為に確認します。

5

モジュラーJARの依存性、公開範囲、メインクラスなどの情報に間違いが無いことを確認することができました。

依存性の定義にjava.baseモジュールがありますがこれはjava.lang.Objectクラスなどが含まれた必要不可欠なもので全てのモジュールに含まれることになります。

greeting@1.0.jarでは非公開パッケージがcontains jp.yucchi.greeting.internalと表示されています。

ここでJava SE 9からjarコマンドが少し変更されているのでヘルプをみておきましょう。

yucchi@ubuntu:~/Documents/MyJigsawProjects/HelloJigsaw$ jar –help
使用方法: jar [OPTION…] [ [–release VERSION] [-C dir] files] …
jarはクラスおよびリソースのアーカイブを作成し、アーカイブから個々のクラスまたは
リソースを操作または復元できます。

例:
# 2つのクラス・ファイルを含むclasses.jarというアーカイブを作成する:
jar –create –file classes.jar Foo.class Bar.class
# foo/のすべてのファイルを含む、既存のマニフェストを使用したアーカイブを作成する:
jar –create –file classes.jar –manifest mymanifest -C foo/ .
# モジュラjarアーカイブを作成する。モジュール・ディスクリプタはclasses/module-info.classに
# ある:
jar –create –file foo.jar –main-class com.foo.Main –module-version 1.0
     -C foo/ classes resources
# 既存の非モジュラjarをモジュラjarに更新する:
jar –update –file foo.jar –main-class com.foo.Main –module-version 1.0
     -C foo/ module-info.class
# 複数リリースjarを作成し、一部のファイルをMETA-INF/versions/9ディレクトリに配置する:
jar –create –file mr.jar -C foo classes –release 9 -C foo9 classes

jarコマンドを短縮または簡略化するには、個別のテキスト・ファイルで引数を指定し、
記号(@)を接頭辞として使用してjarコマンドに渡します。

例:
# 追加オプションおよびクラス・ファイルのリストをファイルclasses.listから読込みます
jar –create –file my.jar @classes.list

メイン操作モード:

  -c、–create               アーカイブを作成します
  -i,、–generate-index=FILE  指定のjarアーカイブの索引情報を
                             生成します
  -t、–list                 アーカイブの内容を一覧表示します
  -u、–update               既存のjarアーカイブを更新します
  -x、–extract              指定の(またはすべての)ファイルをアーカイブから抽出します
  -d, –describe-module      モジュール・ディスクリプタまたは自動モジュール名を出力します

どのモードでも有効な操作修飾子:

  -C DIR                     指定のディレクトリに変更し、次のファイルを
                             取り込みます
  -f、–file=FILE            アーカイブ・ファイル名。省略した場合、stdinまたは
                             stdoutのいずれかが操作に基づいて使用されます
      –release VERSION      次のすべてのファイルをjarのバージョニングされたディレクトリ
                             (つまり、META-INF/versions/VERSION/)に配置します
  -v、–verbose              標準出力に詳細な出力を生成します

作成または更新モードでのみ有効な操作修飾子:

  -e、–main-class=CLASSNAME モジュラまたは実行可能なjarアーカイブに
                             バンドルされたスタンドアロン・アプリケーションの
                             アプリケーション・エントリ・ポイント
  -m、–manifest=FILE        指定のマニフェスト・ファイルからマニフェスト情報を
                             取り込みます
  -M、–no-manifest          エントリのマニフェスト・ファイルを作成しません
      –module-version=VERSION    モジュラjarの作成時または非モジュラjarの更新時の
                             モジュール・バージョン
      –hash-modules=PATTERN モジュラjarの作成時または非モジュラjarの更新時に
                             指定のパターンに一致し、直接または間接的に
                             依存しているモジュールのハッシュを
                             計算および記録します
  -p、–module-path          ハッシュを生成するモジュール依存性
                             の場所

作成、更新および索引生成モードでのみ有効な操作修飾子:

  -0, –no-compress          格納のみ。ZIP圧縮を使用しません

その他のオプション:

  -h、–help[:compat]        これ(オプションで互換性)をhelpに指定します
      –help-extra           追加オプションのヘルプを提供します
      –version              プログラム・バージョンを出力します

モジュール・ディスクリプタ’module-info.class’が指定のディレクトリのルートまたは
jarアーカイブ自体のルートにある場合、アーカイブはモジュラjarです。
次の操作は、モジュラjarの作成時または既存の非モジュラjarの更新時に
のみ有効です:  ‘–module-version’、
‘–hash-modules’および’–module-path’。

ロング・オプションへの必須またはオプションの引数は、対応するショート・オプション
に対しても必須またはオプションになります。

Project Jigsawの影響でコマンドが増えていますね。(当たり前か・・・)

最後にこのプログラムを実行してみます。


java --module-path mods --module jp.yucchi.hello

6

アプリケーション・エントリ・ポイントを設定したモジュールのモジュールパスとモジュール名を指定してjavaコマンドによって実行します。

今回はモジュラーJAR作成時にアプリケーション・エントリ・ポイントを指定してますのでこのように実行できます。

モジュラーJAR作成時にアプリケーション・エントリ・ポイントを設定してない場合は次のように実行します。

モジュールのモジュールパスの指定はおなじです。

–module モジュール名/モジュールのメイン・クラス名とアプリケーション・エントリ・ポイント指定しなければいけません。

7

ついでだから javaコマンドのヘルプも確認しておきます。

 

yucchi@ubuntu:~/Documents/MyJigsawProjects/HelloJigsaw$ java –help
使用方法: java [options] <mainclass> [args…]
           (クラスを実行する場合)
   または  java [options] -jar <jarfile> [args…]
           (jarファイルを実行する場合)
   または  java [options] -m <module>[/<mainclass>] [args…]
       java [options] –module <module>[/<mainclass>] [args…]
           (モジュールのメイン・クラスを実行する場合)

メイン・クラス-jar <jarfile>、-mまたは–module
<module>/<mainclass>に続く引数は、メイン・クラスへの引数として渡されます。

オプションは次のとおりです:

    -d32      推奨されていません。今後のリリースで削除される予定です
    -d64      推奨されていません。今後のリリースで削除される予定です
    -cp <ディレクトリおよびzip/jarファイルのクラス検索パス>
    -classpath <ディレクトリおよびzip/jarファイルのクラス検索パス>
    –class-path <ディレクトリおよびzip/jarファイルのクラス検索パス>
                  :区切りリスト(ディレクトリ、JARアーカイブ、
                  ZIPアーカイブ)で、クラス・ファイルの検索用。
    -p <module path>
    –module-path <module path>…
                  ディレクトリの:区切りリスト、各ディレクトリ
                  はモジュールのディレクトリです。
    –upgrade-module-path <module path>…
                  ディレクトリの:区切りリスト、各ディレクトリ
                  は、ランタイム・イメージ内のアップグレード可能な
                  モジュールを置換するモジュールのディレクトリです
    –add-modules <module name>[,<module name>…]
                  初期モジュールに加えて解決するルート・モジュール。
                  <module name>には次も指定できます: ALL-DEFAULT、ALL-SYSTEM、
                  ALL-MODULE-PATH.
    –list-modules
                  参照可能なモジュールをリストし終了します
    -d <module name>
    –describe-module <module name>
                  モジュールを説明し終了します
    –dry-run     VMを作成しメイン・クラスをロードしますが、メイン・メソッドは実行しません。
                  –dry-runオプションは、次の検証に役立つ場合があります:
                  モジュール・システム構成などのコマンド行オプション。
    –validate-modules
                  すべてのモジュールを検証し終了します
                  –validate-modulesオプションは、次の検索に役立つ場合があります:
                  モジュール・パス上のモジュールでの競合およびその他のエラー。
    -D<name>=<value>
                  システム・プロパティを設定します
    -verbose:[class|module|gc|jni]
                  詳細出力を有効にします
    -version      製品バージョンをエラー・ストリームに出力して終了します
    –version     製品バージョンを出力ストリームに出力して終了します
    -showversion  製品バージョンをエラー・ストリームに出力して続行します
    –show-version
                  製品バージョンを出力ストリームに出力して続行します
    –show-module-resolution
                  起動時にモジュール解決出力を表示します
    -? -h -help
                  このヘルプ・メッセージをエラー・ストリームに出力します
    –help        このヘルプ・メッセージを出力ストリームに出力します
    -X            追加オプションのヘルプをエラー・ストリームに出力します
    –help-extra  追加オプションのヘルプを出力ストリームに出力します
    -ea[:<packagename>…|:<classname>]
    -enableassertions[:<packagename>…|:<classname>]
                  指定した粒度でアサーションを有効にします
    -da[:<packagename>…|:<classname>]
    -disableassertions[:<packagename>…|:<classname>]
                  指定した粒度でアサーションを無効にします
    -esa | -enablesystemassertions
                  システム・アサーションを有効にします
    -dsa | -disablesystemassertions
                  システム・アサーションを無効にします
    -agentlib:<libname>[=<options>]
                  ネイティブ・エージェント・ライブラリ<libname>をロードします。例: -agentlib:jdwp
                  -agentlib:jdwp=helpも参照してください
    -agentpath:<pathname>[=<options>]
                  フルパス名を使用して、ネイティブ・エージェント・ライブラリをロードします
    -javaagent:<jarpath>[=<options>]
                  Javaプログラミング言語エージェントをロードします。java.lang.instrumentを参照してください
    -splash:<imagepath>
                  指定されたイメージを含むスプラッシュ画面を表示します
                  HiDPIスケールのイメージが自動的にサポートされて使用されます
                  (可能な場合)。スケーリングされないイメージのファイル名(image.extなど)を
                  引数として-splashオプションに必ず渡す必要があります。
                  指定された最も適切なスケーリング済イメージが選択されます
                  (自動的)。
                  詳細は、SplashScreen APIのドキュメントを参照してください
    @argumentファイル
                  オプションを含む1つ以上の引数ファイル
    -disable-@files
                  さらなる引数ファイル拡張を無効にします
長いオプションの引数を指定する場合、–<name>=<value>または
–<name> <value>を使用できます。

まとめ

今回は何も考えずにほぼ写経しただけなので随分楽に進みました。

しかし、モジュール化のメリットの依存性、公開範囲の制限を定義することを学ぶことができました。(^_^)

module-info.javaにrequiresとexportsを記述して依存と公開の定義をする。

requires モジュール名;とすることで指定したモジュールに依存することを定義します。

今回は使っていませんがrequires transient モジュール名;とすることで推移的依存(依存したモジュールの依存先も依存可能)を定義できます。

また、requires static モジュール名;とすることでコンパイル時のみ依存可能と定義できます。

ちょっと複雑に感じますが慣れてくると便利に依存を定義することができそうですね。

次に公開するパッケージを定義するのにexports パッケージ名;と記述します。

exports パッケージ名 to モジュール名;とすることで特定のモジュールに公開することが可能です。

 

ゆっくり少しずつだけどお勉強を進めていこう。

Jigsaw のお勉強 その1

Jigsaw のお勉強 その2

Hatena タグ:

Jigsaw のお勉強 その2

Java

Jigsaw のお勉強の続きです。

前回はクイックスタートガイドを機械翻訳にかけて斜め読みしただけなので今回は実際にプログラムを組んで動かしてみたいと思います。

とりあえず最小構成で試してみます。

次のような標準出力に文字列を表示させるだけのプログラムです。

s1

プログラムのディレクトリ構造は次のようにしてみました。

s2

module-info.java をパッケージのトップディレクトリに作成します。

これだけで Java Platform Module System アプリケーションができてしまいます。

モジュール名に関しては通常のパッケージ名と同じようにユニークになるようにドメイン名ベースとするのが好ましいという意見とそこまでする必要は無いという意見があり、今後どのような命名が一般的になるか気になるところです。

今回はお試しプログラムなので firstjigsaw とシンプルなモジュール名としました。

それではコンパイルしてみましょう。

1

ちゃんとコンパイルされて out/firstjigsaw ディレクトリに二つのクラスファイルが作成されました。(^_^)

実行してみます。

4

おおっ! はじめての Jigsaw 動いた!

–module-path でモジュールパスを指定しています。

-m オプションはメインモジュールを指定しています。

スラッシュの後の値は、モジュール内のメインクラスのクラス名です。

–module-path オプションは -p 短縮オプションが使えます。

また、–module オプションは -m 短縮オプションが使えます。

5

次は作成したクラスファイルを使って jar ファイルを mods ディレクトリに作成します。

3

これも問題なく jar ファイルが作成されました。(^_^)

それでは実行してみましょう。

6

jar ファイルも問題なく実行できました。(^_^)

これも短縮オプションが使えるようですね。

モジュールを使ったプロジェクトの不具合の解決の助けになるコマンドオプションも用意されています。

7

カスタムJRE を作成するためのコマンドもあります。

8

今の私にはまだ必要のないものですがちょっと触ってみました。(^_^;

とりあえず、今日はここまで。

初めて Jigsaw のコード書いて動かしただけだけどこれはわたしにとって大きな一歩です!

 

Jigsaw のお勉強 その1

Hatena タグ:

Jigsaw のお勉強 その1

Java

Java SE 9 がリリースされて随分経ちますが Jigsaw は積極的に使ってないのでさっぱり解らないのが現状です。

リリースされる前から注目されていてネット上には記事がちらほら見受けられていました。

それを読んではいたのですが未だに自分でコードを書いたことは無いのでそろそろなんとかしなければいけないと思い、

冷やし中華はじめました!

じゃなくて、Jigsaw はじめました!

とりあえず何から手を付けて良いものか解らないので Project Jigsaw: Module System Quick-Start Guide を読んでみることにしました。

 

Project Jigsaw: Module System Quick-Start Guide

このドキュメントでは、開発者がモジュールを使い始めるための簡単な例をいくつか紹介します。

サンプルコードのファイルパスはスラッシュを使用し、パス区切り子はコロンです。
Microsoft Windowsの開発者は、ファイルパスにバックスラッシュとセミコロンをパス区切り文字として使用する必要があります

  • Greetings
  • Greetings world
  • Multi-module compilation
  • Packaging
  • Missing requires or missing exports
  • Services
  • The linker
  • –patch-module

Greetings

この最初の例はcom.greetingsという名前のモジュールで、単に “Greetings!”を表示します。
モジュールは、モジュール宣言(module-info.java)とメインクラスの2つのソースファイルで構成されています。

慣例により、モジュールのソースコードは、モジュールの名前であるディレクトリにあります。

ソースコードは、次のコマンドでディレクトリmods / com.greetingsにコンパイルされます。

これで、次のコマンドでこの例を実行します。

–module-pathはモジュールパスです。その値はモジュールを含む1つ以上のディレクトリです。 -mオプションは、メインモジュールを指定します。スラッシュの後の値は、モジュール内のメインクラスのクラス名です。

Greetings world

この2番目の例は、モジュール宣言を更新して、org.astroモジュールへの依存関係を宣言します。
モジュールorg.astroはAPIパッケージorg.astroをエクスポートします。

モジュールは一度に1つずつコンパイルされます。
モジュールcom.greetingsをコンパイルするjavacコマンドは、モジュールorg.astroへの参照と、エクスポートされたパッケージの型を解決できるように、モジュールパスを指定します。

この例は、最初の例とまったく同じ方法で実行されます。

Multi-module compilation

前の例では、モジュールcom.greetingsとモジュールorg.astroが別々にコンパイルされていました。 1つのjavacコマンドで複数のモジュールをコンパイルすることもできます

Packaging

これまでの例では、コンパイルされたモジュールの内容がファイルシステム上で展開されています。
移植と配備の目的では、通常、モジュールをモジュラーJARとしてパッケージ化する方が便利です。
モジュラーJARは、トップレベルのディレクトリにmodule-info.classを持つ通常のJARファイルです。
次の例では、org.astro@1.0.jarおよびcom.greetings.jarをmlibディレクトリに作成します。

この例では、モジュールorg.astroは、そのバージョンが1.0であることを示すようにパッケージ化されています。 モジュールcom.greetingsは、メインクラスがcom.greetings.Mainであることを示すようにパッケージ化されています。 メインクラスを指定することなく、モジュールcom.greetingsを実行できるようになりました。

–module-pathの代わりに-pを使用することによって、コマンドラインも短縮されます。

jarツールには多くの新しいオプションがあります(jar -helpを参照)。その1つはモジュラーJARとしてパッケージ化されたモジュールのモジュール宣言を出力することです。

Missing requires or missing exports

ここで、前の例で、com.greetingsモジュール宣言からの要求を誤って省略した場合の動作を見てみましょう。

このモジュール宣言を修正しましたが、別の間違いを導入しました。
今回はorg.astroモジュール宣言からのエクスポートを省略します。

Services

サービスは、サービスコンシューマモジュールとサービスプロバイダモジュールとの間の疎結合を可能にする。

この例には、サービスコンシューマモジュールとサービスプロバイダモジュールがあります。

モジュールcom.socketは、ネットワークソケット用のAPIをエクスポートします。
このパッケージがエクスポートされるように、APIはcom.socketパッケージ内にあります。
APIは、代替実装を可能にするためにプラガブルです。
サービスタイプは同じモジュール内のクラスcom.socket.spi.NetworkSocketProviderであるため、パッケージcom.socket.spiもエクスポートされます。

モジュールorg.fastsocketはサービスプロバイダモジュールです。
com.socket.spi.NetworkSocketProviderの実装を提供します。
パッケージをエクスポートしません。

以下はcom.socketモジュールのソースコードです。

以下はorg.fastsocketモジュールのソースコードです。

簡単にするために、両方のモジュールをまとめてコンパイルします。 実際には、サービスコンシューマモジュールとサービスプロバイダモジュールは、ほぼ常に別々にコンパイルされます。

最後に、モジュールcom.greetingsを変更してAPIを使用します。

最後に実行します。

出力は、サービスプロバイダが見つかったこと、およびNetworkSocketのファクトリとして使用されたことを確認します。

The linker

jlinkはリンカーツールであり、モジュールのセットとそれらの推移的依存とをリンクしてカスタムモジュラーランタイムイメージを作成するために使用することができます(JEP 220を参照)。

このツールでは、現在、モジュールパス上のモジュールをモジュラーJARまたはJMOD形式でパッケージ化する必要があります。
JDKビルドでは、標準およびJDK固有のモジュールをJMOD形式でパッケージ化します。

次の例では、モジュールcom.greetingsとその推移依存を含むランタイムイメージを作成します。

–module-pathの値は、パッケージ化されたモジュールを含むディレクトリのPATHです。Microsoft Windowsでは パスセパレータ ‘:’を ‘;’に置き換えます。

$ JAVA_HOME / jmodsは、java.base.jmodとその他の標準モジュールとJDKモジュールを含むディレクトリです。

モジュールパス上のディレクトリmlibには、モジュールcom.greetingsの成果物が含まれています。

jlinkツールは、生成されたイメージをカスタマイズするための多くの高度なオプションをサポートしています。詳細はjlink –helpを参照してください。

--patch-module

Doug LeaのCVSからjava.util.concurrentクラスをチェックアウトする開発者は、ソースファイルをコンパイルし、それらのクラスを-Xbootclasspath / pでデプロイするために使用されます。

-Xbootclasspath / pが削除された場合、そのモジュールの置き換えは、モジュール内のクラスを上書きするオプション–patch-moduleです。 また、モジュールの内容を増やすために使用することもできます。 –patch-moduleオプションはjavacでもサポートされており、モジュールのようにコードをコンパイルします。

以下は、新しいバージョンのjava.util.concurrent.ConcurrentHashMapをコンパイルし、それを実行時に使用する例です。

More information

The State of the Module System

JEP 261: Module System

Project Jigsaw

Feedback

Please send usage questions and experience reports to the jigsaw-dev list. Specific suggestions about the design of the module system should be sent to the JSR 376 Expert Group’s comments list.

機械翻訳によって日本語化してみました。

この資料が古くてカビが生えてなければいいのですが・・・ とりあえず読んでみました。

Hatena タグ:

Happy New Year 2018!

Computer Java JavaFX

Happy New Year! May this be a happy and fruitful year.

新年最初のエントリーは JavaFX で IBM Cloud (Bluemix)Watson Personality Insights を利用した人格診断プログラムです。

昨年の 11 月 1 日から IBM Cloud (Bluemix)ライト・アカウントが気楽に使えるようになったので少し遊んでみました。

もう、リリースされてから随分経ちますので参考となる資料がネット上にあるのでググればなんとかそれなりのものは動かせるようです。

と言うことで定番の Twitter のつぶやきを解析して人格診断をおこなうプログラムを組んでみました。

本家サイトではこんなデモがおかれています。

1

自分のアカウントで試そうとしたけどエラーで駄目だったのでサンプルの方ので分析してみました。

2

結果が上のスクリーンショットのようになります。

Watson Personality Insights で得られる結果は下段の 「ビッグファイブ – 個性」、「欲求」、「価値」のデータです。

分析データのスコアに関する説明は以下のようされています。

スコアはすべて百分位数であり、膨大な集団の中での位置を表しています。

たとえば、外向性が90%という結果は、その人が90%外向的であることではなく、100人中その人より外向性の低い人が90人(高い人が10人)ということを意味しています。

データは JSON 形式で返されてきます。

これらの分析データの信頼性はどれ位のものかは想像もつかないのですがなかなか面白そうです。

これらの技術を利用した面白いデモも用意されています。

Science and Star Wars の「自分のライトセーバーの色を見つけよう」です。

3

ヨーダと言えば STAR WARS では生ける伝説と称されるジェダイ・マスターで絶対的存在となっています。

うれしいですね! (^_^)

これはもっと詳しく人格診断してみたくなります。

JavaFX で Watson Personality Insights を利用した人格診断プログラムを作るに当たり、分析データをレーダーチャートを使って表示させることにしました。

ところが JavaFX 標準で用意されているチャートにレーダーチャートは見当たりません。((((;゜Д゜)))))))

しかたないので JFreeChart-FX に期待して見に行ったらレーダーチャートは無かった。(見落としていたらごめんなさい)

これで一気に面倒くささハードルが上がった。

とりあえずレーダーチャートは Canvas にお絵かき対応することにしました。

できあがったプログラムを動かして人格診断を行った結果がこちらです。

4

あれれ? なんか・・・ 酷くないですか?

ヨーダと 71 パーセントも性格が一致しているわりには・・・

まぁ、人工知能が人の発言(ツイート)を分析して人格診断するとこんなもんですねと悔しいから言っておきます。(ヲヒ

せっかく年末の忙しい時期にゴニョゴニョしてプログラム組んだのにこれではあんまりだから現在の日本の内閣総理大臣である安倍晋三氏の人格診断をしてみた。

5

おおっ! ビッグファイブ – 個性 のスコアが凄い!

やはり職業柄か誠実性、外向性のポイント高いですね。

個々のスコアもそうかも知れないと思わせる結果です。(個人の感想です。)

断っておきますが私は政治にあまり詳しくなくこの結果を利用して政治批判や誹謗中傷を行うことを目的としていません。

テレビ等で見聞きする情報をもとにした感想です。

それではもう一人診断してみましょう。

私の好きな歌手の宇多田ヒカルさんです。

6

ビッグファイブ – 個性の知的好奇心、協調性、外向性のポイントが高いですね。

やはり生まれついての芸術家なのでしょう。

さて、この結果から私には個性が足りないことがバレてしまいました。

2018 年は個性をもう少しなんとかする年にしなければ。。。(^_^;

そう言うことでこのプログラムのコードを載せておきます。

ただし、かなり酷いことを平気でしています。

パスワード等はプログラムにハードコーディングしていますのでそこは適宜書き換えてくださいませ。

あと、例外処理もほとんど対処していません。

IBM Cloud (Bluemix)ライト・アカウントでお気楽に Watson Personality Insights を試してみたかったからです。

JavaFX はそれなりに手抜きプログラムにも対応してくれます。(ヲヒ 本当は駄目ですよ(^_^;