The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

コマンドモードアプリケーション

このリファレンスでは、実行して終了するアプリケーションの書き方について説明しています。

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitリポジトリをクローンする: git clone https://github.com/quarkusio/quarkus-quickstarts.git 、または アーカイブ をダウンロードする。

ソリューションは getting-started-command-mode ディレクトリ にあります。

Mavenプロジェクトの作成

まず、以下のコマンドで新しいQuarkusプロジェクトを作成します。

コマンドラインインタフェース
quarkus create app org.acme:command-mode-quickstart \
    --no-code
cd command-mode-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.6.0:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=command-mode-quickstart \
    -DnoCode
cd command-mode-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=command-mode-quickstart"

プロジェクト作成の推奨コマンドラインでは、RESTサーバーを含めないようにするため、codestartsを無効にしています。同様に、code.quarkus.ioを使用してプロジェクトを生成する場合、 MORE OPTIONS → Starter CodeNo を選択して、RESTEasy Reactiveエクステンションを追加しないようにする必要があります。

RESTEasy Reactiveエクステンションは、コードスタートを依頼し、エクステンションを指定しなかった場合のみ、自動的に追加されます。

コマンドモードアプリケーションの作成

終了するアプリケーションを実装するためには、2つの異なるアプローチがあります。

  1. QuarkusApplication を実装し、Quarkusがこのメソッドを自動的に実行するようにします

  2. QuarkusApplication とJava mainメソッドを実装し、Java mainメソッドを使用してQuarkusを起動します

このドキュメントでは、 QuarkusApplication インスタンスをアプリケーション mainと呼び、Java mainメソッドを持つクラスを Java mainと呼びます。

QuarkusのAPIにアクセスできる最もシンプルなコマンドモードのアプリケーションは、以下のようになります:

import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;

@QuarkusMain    (1)
public class HelloWorldMain implements QuarkusApplication {
  @Override
  public int run(String... args) throws Exception {   (2)
    System.out.println("Hello " + args[0]);
    return 0;
 }
}
1 @QuarkusMain のアノテーションは、Quarkusにここがメインエントリポイントであることを伝えます。
2 Quarkus が起動すると run メソッドが呼び出され、アプリケーションが終了すると停止します。

コンテキスト

ContextNotActiveException が発生しましたか?

コマンドモードのアプリケーション(CLIなど)は、例えばHTTPサービスとは少し異なり、コマンドラインからの呼び出しは1回だけです。そのため、複数のリクエストはおろか、 request という概念も存在しません。したがって、リクエストスコープはデフォルトではありません。

アプリケーションBeanやサービスにアクセスするために、 @QuarkusMain インスタンスはデフォルトでapplicationスコープのBeanであることに注意してください。singleton、application、dependentスコープのBeanへのアクセスを持っています。requestスコープを必要とするBeanと対話したい場合は、 run() メソッドに @ActivateRequestContext を記述してください。

リクエストスコープを必要とするBeanと対話したい場合は、 run() メソッドに @ActivateRequestContext アノテーションを追加するだけです。 これにより、 run() は Panache Entity の listAll()query* メソッドにアクセスすることができます。 これがないと、そのようなクラスやBeanにアクセスしたときに ContextNotActiveException を受け取ることになります。

Main method

Java mainでアプリケーション mainを実行したい場合は以下のようになります:

import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.annotations.QuarkusMain;

@QuarkusMain
public class JavaMain {

    public static void main(String... args) {
        Quarkus.run(HelloWorldMain.class, args);
    }
}

これは HelloWorldMain アプリケーション mainを直接実行するのと実質的には同じですが、IDE から実行できるという利点があります。

QuarkusApplication を実装したクラスで Java main がある場合は Java main が実行されます。
Java mainはほとんどロジックを実行せず、アプリケーション mainを起動するだけにすることをお勧めします。開発モードでは、Java mainはアプリケーション mainとは異なるClassLoaderで実行されるので、期待通りの動作をしないかもしれません。

複数のmainメソッド

アプリケーション内に複数のmainメソッドを持ち、ビルド時にそれらの間で選択することが可能です。 @QuarkusMain アノテーションはオプションの 'name' パラメーターを取り、 quarkus.package.main-class ビルド時設定オプションを使用して実行するmainを選択するために使用できます。アノテーションを使用したくない場合は、メインクラスの完全修飾名を指定するために使用することもできます。

デフォルトでは、名前のない(つまり空の文字列) @QuarkusMain が使用されます。もしこれが存在せず、 quarkus.package.main-class も指定されていなければ、Quarkusは自動的にアプリケーションを動かすだけのメインクラスを生成します。

@QuarkusMainname は一意である必要があります(デフォルトの空文字列を含む)。アプリケーション内に複数の @QuarkusMain アノテーションがある場合、名前が一意でないとビルドに失敗します。

コマンドモードのライフサイクル

コマンドモードのアプリケーションを実行する場合、基本的なライフサイクルは以下の通りです:

  1. Quarkusの起動

  2. QuarkusApplication mainメソッドの実行

  3. mainメソッドが返った後にQuarkusをシャットダウンし、JVMを終了します

シャットダウンは常にアプリケーションのメインスレッドがreturnされることで開始されます。起動時に何らかのロジックを実行して、通常のアプリケーションのように実行したい場合 (つまり終了しない) は、メインスレッドから Quarkus.waitForExit を呼び出す必要があります (非コマンドモードのアプリケーションは、基本的に waitForExit を呼び出すだけのアプリケーションを実行しているだけです)。

実行中のアプリケーションをシャットダウンしたいが、メインスレッドにいない場合、メインスレッドのブロックを解除してシャットダウン処理を開始するために Quarkus.asyncExit を呼び出す必要があります。

開発モード

また、コマンドモードのアプリケーションについては、開発モードがサポートされています。 開発モードでアプリケーションを起動すると、コマンドモードアプリケーションが実行されます:

コマンドラインインタフェース
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

コマンドモードのアプリケーションでは、コマンドラインで引数を渡す必要があることが多く、これは開発モードでも可能です:

コマンドラインインタフェース
quarkus dev '--help'
Maven
./mvnw quarkus:dev -Dquarkus.args='--help'
Gradle
./gradlew quarkusDev --quarkus-args='--help'

アプリケーションが停止した後、画面の下に以下のように表示されます:

--
Press [space] to restart, [e] to edit command line args (currently '-w --tags 1.0.1.Final'), [r] to resume testing, [o] Toggle test output, [h] for more options>

スペースバー キーを押せば、アプリケーションが再び起動します。また、 e ホットキーを使って、コマンドライン引数を編集し、アプリケーションを再起動することもできます。

コマンドモードアプリケーションのテスト

コマンドモード・アプリケーションは、 @QuarkusMainTest および @QuarkusMainIntegrationTest のアノテーションを使用してテストすることができます。これらは、 @QuarkusTest および @QuarkusIntegrationTest と同様の方法で動作します。 @QuarkusMainTest は現在のJVM内でCLIテストを実行し、 QuarkusIntegrationTest は生成された実行ファイル(ジャーおよびネイティブの両方)を実行するために使用されます。

上記のCLIアプリケーションの簡単なテストを以下のように書くことができます:

import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainLauncher;
import io.quarkus.test.junit.main.QuarkusMainTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@QuarkusMainTest
public class HelloTest {

    @Test
    @Launch("World")
    public void testLaunchCommand(LaunchResult result) {
        Assertions.assertTrue(result.getOutput().contains("Hello World"));
    }

    @Test
    @Launch(value = {}, exitCode = 1)
    public void testLaunchCommandFailed() {
    }

    @Test
    public void testManualLaunch(QuarkusMainLauncher launcher) {
        LaunchResult result = launcher.launch("Everyone");
        Assertions.assertEquals(0, result.exitCode());
        Assertions.assertTrue(result.getOutput().contains("Hello Everyone"));
    }
}

各テストメソッドは、アプリケーションを自動的に起動するために @Launch のアノテーションを付けるか、手動で起動するために QuarkusMainLauncher のパラメータを持つ必要があります。

これを統合テストで拡張し、ネイティブ実行可能ファイルや実行可能jarをテストするために使用することができます:

import io.quarkus.test.junit.main.QuarkusMainIntegrationTest;

@QuarkusMainIntegrationTest
public class HelloIT extends HelloTest {
}

モック

CDI インジェクションは @QuarkusMainTest テストではサポートされていません。 そのため、QuarkusMock@InjectMock を使用して CDI Bean をモックすることもサポートされていません。

テストプロファイル を活用することで、CDI Beanのモックを作成することが可能です。

例えば、次のテストでは、シングルトン CdiBean1MockedCdiBean1 によってモック化されます:

package org.acme.commandmode.test;

import java.util.Set;

import jakarta.enterprise.inject.Alternative;
import jakarta.inject.Singleton;

import org.junit.jupiter.api.Test;
import org.acme.commandmode.test.MyCommandModeTest.MyTestProfile;

import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainTest;

@QuarkusMainTest
@TestProfile(MyTestProfile.class)
public class MyCommandModeTest {

    @Test
    @Launch(value = {})
    public void testLaunchCommand(LaunchResult result) {
        // ... assertions ...
    }

    public static class MyTestProfile implements QuarkusTestProfile {

        @Override
        public Set<Class<?>> getEnabledAlternatives() {
            return Set.of(MockedCdiBean1.class); (1)
        }
    }

    @Alternative (2)
    @Singleton (3)
    public static class MockedCdiBean1 implements CdiBean1 {

        @Override
        public String myMethod() {
            return "mocked value";
        }
    }
}
1 代替モックビーンを有効にしたい CDI ビーンをすべて列挙します。
2 Alternative@Priority なしで使用します。@Mock を使用しないことを確認してください。
3 モックされたビーンのスコープは、元のビーンと一致する必要があります。

このパターンを使用すると、任意のテストに対して特定の選択肢を有効にすることができます。