NetBeansからHelidonを使う

Helidonです、Helidon。

プロジェクトの作成

HelidonはMavenプロジェクト的には素直なので、Mavenはバンドルの3.3.9で大丈夫です。 プロジェクト作成もNetBeansからできます。

新規作成でjava with MavenからProject from Archetypeを選びます。
f:id:nowokay:20190620004502p:plain

Archetypeの検索でHelidonといれるとSEとMPが出るので、好きなほうを。
ここではSEにします。
f:id:nowokay:20190620004813p:plain

あとは適当にプロジェクト名などを。
f:id:nowokay:20190620005453p:plain

プロジェクトが作成されました。
f:id:nowokay:20190620005633p:plain

ビルドや実行なども通常のプロジェクトどおりメニューから行えます。

Native Imageの作成

Helidon SEはGraalVMのNative Imageに対応していますが、単にjarファイルをnative-imageコマンドでコンパイルはできなかったので、Mavenからネイティブコンパイルを行う必要があります。
ネイティブコンパイルするときは、native-imageプロファイルをActivateする必要があります。
f:id:nowokay:20190620010247p:plain

また、GraalVMのnative-imageコマンドにPATHが通ってる必要があります。バージョンはRC16ではダメでした。19.0.0以降が必要です。
ビルドするとネイティブコンパイルが始まります。
f:id:nowokay:20190620014744p:plain

ただ、native-imageにパスを通したりプロファイルを切り替えたりは面倒なので、Quarkusの場合と同じようにGoalを設定するほうがよさそう。 f:id:nowokay:20190620020356p:plain

この場合、Goalsにはpackage、Profilesにnative-image、PropertiesにEnv.PATHを設定します。
Env.PATHは${Env.PATH}:で始めて既存のパスを有効にする必要があるのと、パスなのでbinまでいれる必要があることに注意してください。Remember Asにnativeなどを設定しておくとメニューから選べるようになります。 f:id:nowokay:20190620020154p:plain

これでプロファイル切り替えをせずにネイティブコンパイルできるようになります。 f:id:nowokay:20190620020824p:plain

ということで、やはり1分20秒くらいかけてネイティブコンパイルできました。 f:id:nowokay:20190620021507p:plain

NetBeansからQuarkusを使う

Quarkusです、Quarkus。

Mavenのアップデート

QuarkusのビルドにはMaven 3.5.3が必要ですが、NetBeans11にバンドルされているMavenは3.3.9なので、そのままではビルドなどができません。
ということで、Mavenの最新版をダウンロードしてどこかに解凍します。
Maven – Download Apache Maven

そしたら、PreferenceのJavaタブでMavenを選んでMavenを解凍したパスを設定します。
f:id:nowokay:20190615014520p:plain

プロジェクトの作成

残念ながら、GUIからのプロジェクト作成は できなさそう。なので、ドキュメント通りにコマンドラインでプロジェクト生成します。

$ mvn io.quarkus:quarkus-maven-plugin::create

そうするとArtifact IDなどを聞かれてくるので、適当に入力していきます。 (もちろん空のMavenやGradleプロジェクトを作成してビルドファイルを編集すれば、プロジェクト作れます。)

実行用Goalの設定

開発時のプロジェクト実行にはquarkus:dev:というGoalを使う必要があります。そのままではNetBeansのメニューからのプロジェクト実行ができません。
なので、プロジェクト実行時に実行されるGoalを指定します。

プロジェクトのプロパティからActionsを選んでRun ProjectのExecute Goalsにquarkus:dev:を指定します。 またSet Propertiesのところにexec.argsでclasspathが指定してあるので、この行は削除しておきます。 f:id:nowokay:20190615015617p:plain

そうすると[F6]などでプロジェクトが実行できるようになります。 f:id:nowokay:20190615020021p:plain

Native Imageの作成

ついでにNative Imageを作れるようにしましょう。 現時点ではGraalVMの最新であるバージョン19ではなく、ひとつ前のRC16が必要です。
Release GraalVM Community Edition 1.0 RC16 · oracle/graal

必須ではないですがJavaプラットフォームとして登録しておきましょう。 f:id:nowokay:20190615020438p:plain

Build->Compileでプロジェクトのプラットフォームとして指定しておくのが無難です。 f:id:nowokay:20190615020551p:plain

ActionsでAdd Customを選んでNativeを追加します。(別の名前でもいいです) f:id:nowokay:20190615020852p:plain

Execute Goalsにpackage -Pnativeを指定します。また、GRAALVM_HOMEを指定しておく必要があります。 f:id:nowokay:20190615020739p:plain

Use JDK for Maven Buildを使うとJAVA_HOMEが埋め込まれるので、それをGRAALVM_HOMEに書き換えるのが楽です。 f:id:nowokay:20190615021549p:plain

そうするとプロジェクトメニューのRun MavenにNativeが追加されるので、ここからNative Imageが作成できるようになります。 f:id:nowokay:20190615021720p:plain

1分ちょっとかかってNative Imageのビルドができました! f:id:nowokay:20190615021805p:plain

Windows(Cygwin)でSDKMANがうまく動かないのはcurlのせい

WindowsCygwin使ってSDKMANを動かしてみたのですが、うまく動きませんでした。
なんかファイルをダウンロードしてるのに、ファイルがみつからないと言ってます。というか、curlがなんか文句いってますね。

$ sdk install micronaut

Downloading: micronaut 1.1.3

In progress...

######################################################################## 100.0%Warning: Failed to create the file 
Warning: /home/naoki/.sdkman/tmp/4ulZL0XaBO5l3DQVqssmcLsZUEZJ4cgQ.bin: No such 
Warning: file or directory
                                                                           0.1%
curl: (23) Failed writing body (0 != 16360)
mv: '/home/naoki/.sdkman/tmp/4ulZL0XaBO5l3DQVqssmcLsZUEZJ4cgQ.bin' を stat できません: No such file or directory

これ、結局はWindowscurlコマンドが入って、cygwin上からWindowscurlコマンドを実行してるためにエラーになってる模様。 WindowsパスのC:/home/naoki/.sdkman...に保存しようとして怒られてるんでしょうね。 ということでCygwinのsetup.exeでcurlをインストールして実行するとうまく動きました。

$ sdk install micronaut

Downloading: micronaut 1.1.3

In progress...

###################################################################################### 100.0%

Installing: micronaut 1.1.3
Done installing!


Setting micronaut 1.1.3 as default.

switch式の値付きbreakはyieldになる?

前のエントリではswitch式で値を返すのはbreak-withになると書いてましたが、yieldにしようぜーという議論が勃発しています。
switch式の値付きbreakはbreak-withになることがほぼ確定(追記あり) - きしだのHatena

というか、JEPはすでにyieldになっています。
JEP 354: Switch Expressions (Preview)

https://mail.openjdk.java.net/pipermail/amber-spec-experts/2019-May/001301.html

これは10日ほど前のBrian Goetz氏からの「自転車置き場の議論やろうぜー」という投稿から議論がはじまっていて、ハイフン付きキーワードだけじゃなくコンテキスト付きキーワードも考慮しようという話です。
Call for bikeshed -- break replacement in expression switch

反論としては yield (1);がyieldメソッドに引数1を渡すのか、(1)をswitch式の結果として返すのかわかりにくいんでは、特にIDEの実装が大変なんでは、というのが出てますね。
Yield as contextual keyword (was: Call for bikeshed -- break replacement in expression switch)

どうなるか興味津々

switch式の値付きbreakはbreak-withになることがほぼ確定(追記あり)

Java12でプレビューとしてswitch式が入って、Java13で正式化できるよう作業が進んでいます。 そんな中、switch式を正式化するJEPのドラフトが出ていました。 JEP draft: Switch Expressions 追記 あっというまにドラフトではなくなっています JEP 354: Switch Expressions

プレビューとの違いはbreakがハイフン付キーワードのbreak-withになるという記述があります。

int result = switch (s) {
    case "Foo": 
        break-with 1;
    case "Bar":
        break-with 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        break-with 0;
};

かなり違和感が・・・
そしてこれは、package-privateとかいろんなキーワードが現れる準備でもありそうです。
引き算と区別ができないんでは?という点について、ハイフン付キーワードは必ずキーワードとの組み合わせになるはずなので、もともと引き算とはみなせなかったので大丈夫です。

5/22追記: break-withじゃなくてyieldになるかも。JEPが変更されています。しかし議論が大盛り上がり中でどこに落ち着くかわからない状況。 switch式の値付きbreakはyieldになる? - きしだのHatena

QuarkusのHibernate ORM with Panacheでid不要ならPanacheEntityBaseを使う

Quarkusを試していて、Hibernate ORM with Panacheを使ってみると、ちょっとハマった。

こんな感じのEntityクラスを作った。

@Entity
@Table(name = "users")
@Data
public class User extends PanacheEntity {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;

    @Column(name = "user_name")
    private String userName;

   ...

そうするとUser.listAll()を呼び出したときにこんなエラー。idフィールドがないと言ってる。

Caused by: org.postgresql.util.PSQLException: ERROR: column user0_.id does not exist

いろいろ試したのだけど、なんのことはない、PanacheEntityidが定義されているので、代わりにPanacheEntityBaseを使えばよかった。

@Entity
@Table(name = "users")
@Data
public class User extends PanacheEntityBase {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;

    @Column(name = "user_name")
    private String userName;

   ...

jpackageでJavaアプリのインストーラーを作る

Javaアプリケーションのインストールパッケージを作れるjpackageが、どうもJDK13に入りそうな勢いでEarly Accessが出てたので試してみます。
jpackageは、JavaFXにあったjpackagerをベースにしたパッケージングツールです。
JEP 343: Packaging Tool

EAはこちらからダウンロードできます。開発中のJDK13をベースにしてると書いてありますね。
jpackage

Windowsで必要なもの

Windowsインストーラーを作るには、iscc.exeが必要で、これはInno Setupに入ってます。
jrsoftware.org // Jordan Russell's Software

あと、MSI形式のインストーラーを作るにはlight.exeとcandle.exeが必要で、これはWix toolsに入ってます。
WiX Toolset
zipでwix311-binaries.zipをダウンロード・解凍してパスを通すのがいいと思います。

インストーラを作る

ではインストーラを作ってみます。
とりあえずウィンドウを作るアプリを作ってみます。

import javax.swing.*;

public class MyFrame {
    public static void main(String[] args) {
        var f = new JFrame("My Package");
        var t = new JTextArea();
        f.add(t);
        var b = new JButton("Hello");
        f.add("North", b);
        b.addActionListener(al -> t.append("Hello\n"));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(500, 400);
        f.setVisible(true);
    }
}

ボタンを押すとHelloと表示されるだけのアプリ
実行画面

jpackageではclassファイル単体ではパッケージを作れないようなので、一度jarを作ります。

> javac MyFrame.java

> mkdir target

> jar -cf target/mypack.jar MyFrame.class

そしたら、jpackageでインストーラを作成

>jpackage create-installer -ooutput pack -input target --name MyApp --main-class MyFrame --main-jar mypack.jar
Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed
 by either disabling realtime monitoring, or adding an exclusion for the directory "C:\Users\naoki\AppData\Local\Temp\".
Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed
 by either disabling realtime monitoring, or adding an exclusion for the directory "C:\Users\naoki\AppData\Local\Temp\".
Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed
 by either disabling realtime monitoring, or adding an exclusion for the directory "C:\Users\naoki\AppData\Local\Temp\".

こんな感じでexeとmsiインストーラができています。--typeで形式を指定することもできます。

>dir pack
 C:\Users\naoki\Documents\mypack\pack のディレクトリ

2019/03/06  05:39    <DIR>          .
2019/03/06  05:39    <DIR>          ..
2019/03/06  05:38        33,266,979 MyApp-1.0.exe
2019/03/06  05:39        53,588,671 MyApp-1.0.msi

exeが33MBでmsiが53MBですね。
exeを実行すると、インストーラ画面がでます。
インストーラ画面

インストール実行すると、あのインストール画面が。
インストール実行

スタートメニューにも追加されています。 スタートメニュー

もちろん、このアイコンをクリックすれば起動します。
実行画面

ところで、msiをダブルクリックするといきなりインストール始まるので注意です。

ファイルはWindowsの場合C:\Program Filesにインストールされます。
jshell.exeなど、JDKのファイルも含まれてることがわかります。 JDKもインストールされる

JDKまるごと含まれてると考えたら、50MBでインストーラは妥当な感じですね。

「アプリと機能」からアンインストールもできます。
アプリと機能

JDKだけのインストーラも作れるみたい。なかなか便利ですね。