ひらおかゆみのなげやりブログ

もう、なげやりです…

お久しぶりです

お久しぶりです。

最近何かと忙しくて、Twitterとかほとんど見れていませんでした。

これからもっと忙しくなりそうなので、何年か前に作りかけで放置したJavaMailのラッパー・ライブラリをとりあえず仕上げました。

github.com

その昔、JavaFXでメールクライアントを作ろうとして出来上がらなかった時から、細々とは作っていたのですが、他のことが優先で延び延びになっていました。ちゃんとテストをしていないのでおかしい動きをするかもしれませんが、ちょっと動かした感じではメール送受信ともうまくいきました。

アピールポイント:

  • メール送信なら最短1行のコードでOK。
  • メール受信も可。添付ファイルも扱えます。
  • プリセットの設定 (SMTP/POP3/IMAP) を使えば、Jakarta Mail (JavaMail) のプロパティを知らなくても大丈夫。
  • 既存のメール・セッションや、MailSessionDefinitionアノテーションから設定を読み込むことも可能。

またしばらくは更新できないと思うので、使えそうだったら使ってみてください。

2019年の誕生日

今日は、わたしの20代最後の誕生日です。

前回の記事がちょうど1年前の誕生日でした。

 

この1年間で、何もできなかった。

この先もずっと、何もできないんじゃないかと思うと、自分は何のために生まれてきたのかわからなくなります。

 

先日「バビロン」というアニメを見ました。

今のわたしにとても刺さる内容でした。

 

今日は母も祖父母も仕事を休んで、一日わたしと一緒にいてくれるそうです。

 

Java 9で作成したJavaFXアプリケーションをOpenJDK 11+OpenJFX 11用にアップデートする

このエントリは、Java Advent Calendar 2018じゃばえふえっくす Advent Calendar 2018の19日目です。そして今日12月19日はわたしの誕生日でもあります(年齢のことは聞かないお約束です)。さらに約1年ぶりのブログで、Javaに触れるのも1年ぶり、PCに触れるのも数か月ぶりくらいというお久しぶりです。JavaのAdvent Calendarからも以前お見かけした名前はなくなっていて、寒い時代になったと思いませんか?

さて、昨年のJavaFX Advent Calendar 2017では、一昨年にJava 8で作成したJavaFXアプリケーションをJava 9のモジュールに対応させてみました。 

blog.yumix.net

今年は、これをJava 11に対応させてみます。

Javaから約1年間遠ざかっていたので、世の中的にJava 10が存在したことも、Javaが有償化される?されない?で大騒ぎがあったこともよくわかりません。ただ、Java 11から、とても残念なことにJavaFXが削除されてしまいました。とても残念でなりませんが、OpenJFX単独でやっていくようなので、 断腸の思いでこれを受け止めることにします。

Java 11以降でJavaFXを使用するには、別途OpenJFXをインストールする必要があります。基本的な手順については、すでに櫻庭さんがブログでお書きになっています。

skrb.hatenablog.com

skrb.hatenablog.com

櫻庭さんのブログを拝見して、たぶんMavenを使うとOpenJFX SDKを直接インストールしなくてもよさそうなことはわかりました。それでもはっきり言って、敷居が上がっています。超面倒になっていますし、javapackagerもなくなっています。この件に関してはいろいろ言いたいことはありますが、そのままでは前に進めないので、公式ドキュメントを片手にとりあえず進めてみます。 

幸いなことに、昨年頑張ってJava 9のモジュール対応をやった甲斐があってか、 Javaのソースコード自体は変更する必要がありませんでした。修正はpom.xmlだけ、完成形を引用します。

pom.xml of Asteroid Viewer for OpenJFX 11

まず、依存関係に org.openjfx:javafx-controls:11 と org.openjfx:javafx-fxml:11 を指定します。これらがそれぞれモジュール javafx.controls と javafx.fxml に対応します。このほかのモジュールも同じような命名規則で登録されています。

続いて、Mavenプラグインを追加します。maven-compiler-pluginがコンパイルに使うもの、exec-maven-pluginが実行に使うものです。昨年maven-compiler-pluginのバージョンでいろいろあったので、念のため最新版の3.8.0にしました。それから、櫻庭さんのブログにもあるように、exec-maven-pluginを追加して mvn exec:java で実行しないとなぜか動かない仕様?なので、素直に従います。昨年版にはこれ以外に2つプラグインを使っていましたが、今回は出番がないので外しました。

これで動作するようにはなりましたが、「may not be accessible to clients due to missing 'requires transitive'」という警告が残っています。JavaFXのFXMLLoaderクラスとColorクラスを使用しているところのようです。原因がはっきりしないまま放置すると後々痛い目に遭うので、この時点で解決することにしました。

警告メッセージをそのままGoogle検索すると、それらしき情報が見つかります。

stackoverflow.com

とりあえず、module-info.javaでJavaFXのモジュールをインポートしている箇所の「requires」を「requires transitive」に置き換えると警告は出なくなります。これにはモジュールの依存関係が関係しているようで、javafx.controlsモジュールのJavadocを見ると、必要なモジュールjavafx.baseとjavafx.graphicsにそれぞれ「transitive」というModifierが付加されているのがわかります。最終的に解決できればプログラムは実行できますが、「transitive」な依存モジュールがある場合には、「requires transitive」としてあげないと警告が出るようです。Java 9の頃には「requires」で問題なかったため、Java 11でJavaFXが削除されたことで依存関係の定義が変わったのかもしれません。

今回、OpenJFX 11に移行してみてわかったことをまとめます。

  • JavaFXのアプリケーションはモジュール化しておいた方が楽です。JavaFXモジュールの依存関係がMavenの依存関係とほぼ1対1に対応しているので、pom.xmlでしているするときにわかりやすいです。
  • JavaFXアプリケーションのソースコードは基本的に修正する必要はありません。その代わり、pom.xmlは大きな書き換えが必要で、Java 8~9の頃にできたパッケージングも使えなくなり、制限事項はまだ多く残っています。
  • module-info.javaの「requires」と「requires transitive」の違いを意識する必要があるかもしれません。

JavaFXのHTMLEditorの機能と限界

このエントリは、JavaFX Advent Calendar 2017の24日目です。昨日は櫻庭 (@skrb / id:skrb) さんの「ControlsFX 準備編」、明日は櫻庭さんが今年のJavaFX Advent Calendarを締めてくださいます。

今年のわたしは、HTMLEditorを使ったWebオーサリングツールが作れないものかと試行錯誤していました。

最初のエントリはこちら。何も考えずにHTMLEditorで何でもできる?と思って挑戦して挫折したものです。

blog.yumix.net

次に、青江さんからJDK 9でHTMLEditorSkinが公開APIになったから細かい制御ができるよと伺って試してみた結果です。確かにHTMLEditorSkinの存在自体は偉大なのですが、現状機能不足でちょっと力不足だった、というのがこちらのエントリです。

blog.yumix.net

最終手段、リフレクションでHTMLEditorSkinの内部を直接叩こうという試みが今回のエントリになります。なお、リフレクションを使うと言った途端、@khasnuma (@btnrouge) が自作のリフレクション・ユーティリティを勧めてきたのですが…

f:id:yumix_h:20171224032809p:plain

(ごめんなさい、元ネタよく知らないの…)

方法1: リフレクションでHTMLEditorSkin.executeCommand()を呼び出す

HTMLEditorのコマンドは、最終的にはprivateメソッドexecuteCommand()を呼び出しているようです。ということは、リフレクションでexecuteCommand()を呼び出せば何とかなりそう、というのが最初に考えたこと。

ただ、実際にやってみるとうまくゆきませんでした。

private boolean executeCommand(HTMLEditorSkin.Command command) throws Exception {
    Method method = HTMLEditorSkin.class.getDeclaredMethod("executeCommand", String.class, String.class);
    method.setAccessible(true);
    return (Boolean) method.invoke(htmlEditor.getSkin(), Command.COPY.getCommand(), null);
}

@FXML
public void handleCut(ActionEvent event) throws Exception {
    executeCommand(HTMLEditorSkin.Command.CUT);
} 

これはCutコマンドを直接executeCommandでメニューから呼び出した時のコードです。実行結果は…選択範囲をCutするとクリップボードには入るのですが、Cutした文字列が画面から消えない。

CutボタンはHTMLEditorSkin.cutButtonフィールドに対応していて、そのonActionイベントにはexecuteCommandともう1つ処理が含まれていました。たぶん、選択範囲をクリップボードに入れた後に画面から消す処理が別に存在しているのだと思います。

方法2: ボタンのonActionイベントをリフレクションで呼び出す

メニュー選択時にボタンをクリックするアクションをシミュレートすれば同じ結果が得られるはず、ということで試してみました。

private void fireButtonEvent(String buttonName) throws Exception {
    Field field = HTMLEditorSkin.class.getDeclaredField(buttonName);
    field.setAccessible(true);
    Button button = (Button) field.get(htmlEditor.getSkin());
    button.fireEvent(new ActionEvent());
}
    
@FXML
public void handleCut(ActionEvent event) throws Exception {
    fireButtonEvent("cutButton");
} 

これはすんなり通りました。この例はCutのみですが、CopyやPasteについても正しく動作します。リフレクションの警告は鬱陶しいけれど…これでOKとします。

課題

HTMLEditorには他にも様々なボタンが用意されています。ボタン(+ undocumentedなショートカットキー; 一般的なものと同じですが)を使用している限りは、HTMLの編集に関しては必要最低限の機能は揃っているようです。ただし、HTMLEditorSkinでできることが少ない、頑張ってリフレクションを使っても限度がある、ドキュメントに画像を埋め込めない、など過剰な期待は禁物なコントロールであると実感しました(本当なら1回のエントリで完結するはずだったんですよ!)。

わたし的には、おととしのWebViewにチャレンジしたときのほうがおもしろかったかな?

blog.yumix.net

一応、今回までのところをGitHubにアップロードしておきます。現状、これ以上の発展は望めそうにないですけど、ご参考までに。

github.com

追補

昨日の櫻庭さんのエントリにもありましたが、Java 9でリフレクションを使用する場合には、VM引数に --illegal-access=warn を付けましょう。わたしも1つ、勉強になりました。

JavaFXのHTMLEditorSkinはどこまで使えるか?

このエントリは、JavaFX Advent Calendar 2017の22日目です。昨日は@sk44_さんの「業務で JavaFX をちょっとだけ使ってみた」でした。

前回の私のエントリを公開した後、青江 (@aoetk) さんからアドバイスをいただきました。

よし、これでいける!

早速Cutメニューのハンドラを作ってみたのですが、なぜか動かない。こういう時はまずドキュメントを見よう、ということでjavafx.scene.skin.HTMLEditorSkinの項目を見てみます(それにしてもJDK 9のAPIドキュメントは使い勝手が微妙…)。

Special-case handling for certain commands. Over time this may be extended to handle additional commands. The current list of supported commands is:

  • BOLD
  • ITALIC
  • UNDERLINE

 現時点でサポートされているのはBOLD、ITALIC、UNDERLINEだけ、とはっきり書いてありますね。

JavaFX 9では標準コントロールのSkinが公開されたため、コントロールの見栄えを(CSSでできる以上に)カスタマイズできるようになりました。HTMLEditorのスキンであるHTMLEditorSkinもその1つ。ただし、現時点でHTMLEditorSkinにできることは、

  • レイアウトの微調整
  • BOLD、ITALIC、UNDERLINEボタンの制御

だけでした。ほかのボタンの制御も早くサポートされるといいな。

ここで終わるのも悔しい(&12/24に書くことがなくなる)ので、HTMLEditorSkinの内部にリフレクションAPIでアクセスして、どうにかできないものか試してみます。

CDI 2.0をJava SEから使ってみる

このエントリは、Java Advent Calendar 2017の17日目(遅刻&代行)です。本当は19日目担当でしたが、何日も前に書き終えて下書きのまま忘れていました。@ukiuniさん、お手数をおかけしてすみません。

以前からWeld SEという、CDIをJava SEでも使えるようにしてくれるライブラリを存じいていたのですが、秋に登場したJava EE 8に含まれるCDI 2.0にはJava SEでも使用できるAPIがあると耳にしたので、せっかくなので試してみました。わたしのCDIに対する理解は浅くて、

  • インスタンスの代入をよろしくやってくれる仕組み
  • インスタンスの生存期間をある程度制御できる仕組み

くらいにしか思っていないのですが、とりあえず試してみます。

準備

Java SEでCDI 2.0を使えるようにするためには、pom.xmlにちょこっと追記が必要です。

<dependency>
  <groupId>javax.enterprise</groupId>
  <artifactId>cdi-api</artifactId>
  <version>2.0</version>
</dependency>
<dependency>
  <groupId>org.jboss.weld.se</groupId>
  <artifactId>weld-se-shaded</artifactId>
  <version>3.0.0.Final</version>
</dependency>

最初のはCDI 2.0のAPIですね。2番目は名前からしてWeld SEそのものと思われます。たぶんですが、Weld SEが基となってCDI 2.0のJava SE向け機能が作られたのだと思います。

実はそれだけでは動かなくて、META-INF/beans.xmlを作成してあげないといけないようです。わたしの環境 (Eclipse Oxygen 1a) では CDI 2.0 用のbeans.xmlは生成できないのですが、CDI 1.1用のものを使用しても特に問題はなさそうです。

そしていよいよJavaのプログラミングですが、今回は簡単にメッセージを返すだけのCDI Beanを順に呼び出すものを作成してみました。

  • Bootstrap - メインクラス、CDIの初期化とEntryPointのインスタンス生成を行う
  • EntryPoint - HelloMessageからメッセージを集めて返すCDI Bean
  • Hello - "Hello"を返すDependentスコープのCDI Bean
  • Message - "Greeting"を返すApplicationスコープのCDI Bean

ソースコードはGitHubにアップロードしましたので、そちらを参照してください。

github.com

CDIがJava SEでも使えるようになり、Java EEで培われたテクニックが使えるようになることはとても素晴らしいことだと思います。以前からWeld SEに注目していたわたしとしては、この新しいAPIに多いな期待を寄せています。

さて、最後にCDIをJava SEで使用する上での注意点です。当然ですが、Java EEで当たり前のように使える機能の一部はJava SEではサポートされません。一例をあげると、スコープを規定するアノテーションは、Java SEでは@Dependentと@ApplicationScopedしか使用できません。@Singletonが使用できなかったのは意外ですが、@RequestScopedや@SessionScopedなどはWebシステム固有のスコープだったため、サポートされなくても仕方ないと割り切っています(必要とされる場面も思い浮かびませんし)。また、Java EE 7以降はbeans.xmlを省略可能ですが、前述の通りJava SEではbeans.xmlが必須です。適当に書いても動きそうなので、プロジェクトを作成したら忘れないうちに入れておきましょう。

その他、CDIに関する注意事項はだいたいJava SE環境でも当てはまるようです。

 

JavaFXのHTMLEditorはどこまで使えるか?

このエントリは、JavaFX Advent Calendar 2017 の 16 日目です。昨日は平田あづみ(@planet_az / id:planet-az)でした。明日は@opengl_8080さんです。

JavaFXにはHTMLEditorというそのものずばりなコントロールが付属しています。HTMLの編集と入出力、印刷ができるようです。これがあればホームページビルダーみたいなソフトを簡単に自作できるのでは?ということでちょっと試してみました。

とりあえず作ってみたのがこれです。Scene Builderの最新版にメニュー付き画面のテンプレートが用意されているので、それを使ってみました。

f:id:yumix_h:20171213003612p:plain

見た目だけなら割と本格派です。実際にワードパット並みの編集機能は持っています。何となくですが使えそうな気にはさせてくれます。

ただ、このHTMLEditorには1つ問題があって、カット・コピー&ペーストやらフォントやら段落書式やら編集操作はいろいろできるのですが、それらをプログラムから制御することができません。例えば、メニューからカット・コピー&ペーストを行おうにも、メニューから呼び出すためのインタフェースがHTMLEditorには備わっていません。

悔しいので深く追っていくと、HTMLEditorは処理のほとんどをHTMLEditorSkinというクラスに委ねていることがわかります。いわゆるhas-Aの関係です。さらにHTMLEditorSkinを見ていくと、内部でWebViewクラスとWebPageクラスを使っていることがわかります。WebPageはWebView内部から呼び出されるクラスで、HTMLEditorSkinからも直接呼び出されます。どうやらHTMLEditorはHTMLの編集にWebViewの内部機能(たぶんWebKit)を用いているようです。HTMLEditorが生成するHTMLはこんな感じになります。

f:id:yumix_h:20171213005838p:plain

見づらい…でも、自動生成したHTMLにインデントや改行を求めてはいけませんよね…

HTMLEditorの様々なボタンは、HTMLEditorSkinがprivateフィールドで保持しているようです。リフレクションを使ってprivateフィールドに強引にアクセスするのはSIer辞めてPayaraに移った例の人が大好きな手法ですが(あの人確か4~5年くらいリフレクションのユーティリティをスクラップ&ビルドしてたはず)、わたしは今のところやるつもりはないです。

HTMLEditorはJava 9からjavafx.webモジュールに含まれているのですが、なぜjavafx.webに分類されたのか、今回の結果でわかったような気がします。

今回作成した(正確には作成途中というべきか?)アプリケーションは、GitHubにアップロードしています。

github.com