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

CDI 統合ガイド

CDI コンテナーである ArC はビルド時にブートストラップされます。このアプローチの欠点は、CDI Portable Extensionsをサポートできないことです。それにもかかわらず、Quarkus固有のエクステンションAPIを使用して機能を実現することができます。

コンテナーは複数のフェーズでブートストラップされます。高レベルの視点から見ると、これらのフェーズは以下のようになります。

  1. 初期化

  2. Beanディスカバリ

  3. 合成コンポーネントの登録

  4. バリデーション

初期化 フェーズでは、準備作業が行われ、カスタムコンテキストが登録されます。その後、コンテナーがすべてのアプリケーションクラスを分析し、Beanを識別し、提供されたメタデータに基づいてそれらをすべて繋ぎ合わせるプロセスがBean ディスカバリ です。その後、エクステンションは 合成コンポーネント を登録することができます。これらのコンポーネントの属性はエクステンションによって完全に制御されます。最後に、 デプロイメントが検証されます 。例えば、コンテナーはアプリケーション内のすべての注入ポイントを検証し、与えられた必要な型と修飾子を満たすBeanがない場合はビルドを失敗させます。

追加のロギングを有効にすることで、ブートストラップに関するより多くの情報を見ることができます。-X または --debug で Maven ビルドを実行し、 io.quarkus.arc を含む行を grep するだけです。開発モード では、quarkus.log.category."io.quarkus.arc.processor".level=DEBUG を使用することができ、2 つの特別なエンドポイントも自動的に登録され、JSON 形式でいくつかの基本的なデバッグ情報を提供します。

Quarkusのビルドステップでは、さまざまなビルドアイテムを生成したり消費したりして、各フェーズにフックすることができます。以下のセクションでは、関連するすべてのビルド項目と一般的なシナリオについて説明します。

1. メタデータソース

クラスとアノテーションは、Bean レベルのメタデータの主要なソースです。初期のメタデータは、Bean の Beanディスカバリ 時に様々なソースから構築される不変の Jandexインデックス である _Beanアーカイブインデックス から読み込まれます。しかし、エクステンションは、ブートストラップの特定の段階でメタデータを追加、削除、変換することができます。さらに、エクステンションは synthetic components を登録することもできます。これは、CDI コンポーネントを Quarkus に統合する際に実現すべき重要な側面です。

このようにして、エクステンションは、そうでなければ無視されていたクラスをBeanに変えたり、その逆を行ったりすることができます。例えば、 @Scheduled メソッドを宣言するクラスは、たとえそれがBean定義アノテーションでアノテーションされておらず、通常は無視されるようなクラスであっても、常にBeanとして登録されます。

2. ユースケース - クラスがBeanとして認識されません

UnsatisfiedResolutionException は、タイプセーフ解決 時に問題があることを示しています。クラスパス上にインジェクションが可能なクラスがあっても、インジェクションポイントを満たすことができないことがあります。クラスが認識されない理由はいくつかありますが、それを解決する方法もいくつかあります。最初のステップでは、その 理由 を特定する必要があります。

2.1. 理由1 :クラスが発見されない

Quarkusには 簡易ディスカバリ があります。クラスがアプリケーションのインデックスに含まれていないことが起こるかもしれません。例えば、Quarkusエクステンションの ランタイムモジュール のクラスは自動的にインデックス化されません。

解決策AdditionalBeanBuildItem .このビルド項目は、ディスカバリー中に解析する1つ以上の追加クラスを指定するために使用することができます。追加のBean・クラスは、コンテナーによって処理されるアプリケーション・インデックスに透過的に追加されます。

cdi-reference および cdi-reference で説明されているように、 @IfBuildProfile, @UnlessBuildProfile, @IfBuildProperty および @UnlessBuildProperty アノテーションを介して、条件付きで追加のBeanを有効化/無効化することはできません。エクステンションは、設定または現在のプロファイルを検査し、本当に必要な場合にのみ AdditionalBeanBuildItem を生成するべきです。
AdditionalBeanBuildItem の例
@BuildStep
AdditionalBeanBuildItem additionalBeans() {
     return new AdditionalBeanBuildItem(SmallRyeHealthReporter.class, HealthServlet.class)); (1)
}
1 AdditionalBeanBuildItem.Builder は、より複雑なユースケースに使用することができます。

AdditionalBeanBuildItem 経由で追加された Bean クラスは、デフォルトでは 取り外し可能です 。コンテナーがそれらを unused とみなした場合、それらはただ無視されます。しかし、 AdditionalBeanBuildItem.Builder.setUnremovable() メソッドを使用して、このビルド項目を介して登録されたBeanクラスを絶対に削除しないようにコンテナーに指示することができます。詳細は、未使用のBeanの削除 および 理由3: クラスが検出され、Bean 定義のアノテーションがあるが削除されている も参照してください。

AdditionalBeanBuildItem.Builder#setDefaultScope() からデフォルトのスコープを設定することも可能です。デフォルトのスコープは、Beanクラスにスコープが宣言されていない場合にのみ使用されます。

デフォルトスコープが指定されていない場合は @Dependent 擬似スコープが使用されます。

2.2. 理由2 : クラスは発見されたが、Beanを定義するアノテーションがない

Quarkusでは、アプリケーションは Bean 検出モード annotated でアノテーションされた単一の Bean アーカイブで表現されます。したがって、 Bean 定義アノテーション を持たない Bean クラスは無視されます。Bean 定義アノテーションはクラスレベルで宣言され、スコープ、ステレオタイプ、 @Interceptor を含みます。

解決策1 : AutoAddScopeBuildItem の使用。このビルドアイテムを使用すると、特定の条件を満たすクラスにスコープを追加することができます。

AutoAddScopeBuildItem の例
@BuildStep
AutoAddScopeBuildItem autoAddScope() {
   return AutoAddScopeBuildItem.builder().containsAnnotations(SCHEDULED_NAME, SCHEDULES_NAME) (1)
      .defaultScope(BuiltinScope.SINGLETON) (2)
      .build();
}
1 @Scheduled でアノテーションされたすべてのクラスを検索
2 デフォルトのスコープとして @Singleton を追加。既にスコープでアノテーションされているクラスは自動的にスキップされます。

解決策2: 特定のアノテーションが付けられたクラスを処理する必要がある場合は、BeanDefiningAnnotationBuildItem を介して Bean 定義アノテーションのセットを拡張することができます。

BeanDefiningAnnotationBuildItem の例
@BuildStep
BeanDefiningAnnotationBuildItem additionalBeanDefiningAnnotation() {
   return new BeanDefiningAnnotationBuildItem(Annotations.GRAPHQL_API); (1)
}
1 Bean 定義アノテーションのセットに org.eclipse.microprofile.graphql.GraphQLApi を追加します。

BeanDefiningAnnotationBuildItem を介して追加された Bean クラスは、デフォルトでは 削除不可 です。したがって、結果の Bean は未使用と見なされても削除しないでください。ただし、デフォルトの動作は変更できます。詳細についてはRemoving Unused Beans および理由3: クラスが検出され、Bean 定義のアノテーションがあるが削除されている を参照してください。

デフォルトスコープを設定することもできます。デフォルトスコープは、Bean クラスにスコープが宣言されていない場合にのみ使用されます。

デフォルトスコープが指定されていない場合は @Dependent 擬似スコープが使用されます。

2.3. 理由3: クラスが検出され、Bean 定義のアノテーションがあるが削除されている

デフォルトで、コンテナーはビルド時に remove all unused beans を試行します。この最適化により、フレームワークレベルでのデッドコードの排除 が可能になります。いくつかの特殊なケースでは、未使用の Bean を正しく特定できません。特に、Quarkus はまだ CDI.current() 静的メソッドの使用を検出できません。エクステンションは、UnremovableBeanBuildItem を生成することで、誤検出の可能性をなくすことができます。

UnremovableBeanBuildItem の例
@BuildStep
UnremovableBeanBuildItem unremovableBeans() {
   return UnremovableBeanBuildItem.targetWithAnnotation(STARTUP_NAME); (1)
}
1 @Startup でアノテーションされたすべてのクラスを削除できないようにする。

3. ユースケース - アノテーションが修飾子またはインターセプターバインディングとして認識されない

アノテーションクラスがアプリケーションインデックスに含まれていない可能性があります。たとえば、Quarkus エクステンションの ランタイムモジュール のクラスは自動的にインデックス化されません。

解決策: 理由1 :クラスが発見されない で説明されているとおりに AdditionalBeanBuildItem を使用します。

4. ユースケース - メタデータを変換する必要があります

場合によっては、メタデータを変更できると便利です。Quarkus は、 javax.enterprise.inject.spi.ProcessAnnotatedType の強力な代替手段を提供します。AnnotationsTransformerBuildItem を使用すると、Bean クラスに存在するアノテーションをオーバーライドできます。

たとえば、特定の Bean クラスにインターセプターバインディングを追加するとします。以下はその方法です。

AnnotationsTransformerBuildItem の例
@BuildStep
AnnotationsTransformerBuildItem transform() {
   return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {

      public boolean appliesTo(org.jboss.jandex.AnnotationTarget.Kind kind) {
         return kind == org.jboss.jandex.AnnotationTarget.Kind.CLASS; (1)
      }

      public void transform(TransformationContext context) {
         if (context.getTarget().asClass().name().toString().equals("org.acme.Bar")) {
            context.transform().add(MyInterceptorBinding.class).done(); (2)
         }
      }
    });
}
1 トランスフォーマーはクラスにのみ適用されます。
2 クラス名が org.acme.Bar と同じ場合は、@MyInterceptorBinding を追加します。Transformation#done() を呼び出すことを忘れないでください。
アノテーショントランスフォーマーは、Beanディスカバリが始まる 前に 生成されなければならないことを覚えておいてください。

ビルドステップでは、TransformedAnnotationsBuildItem を介して、特定のアノテーションターゲットの変換済みアノテーションをクエリーできます。

TransformedAnnotationsBuildItem の例
@BuildStep
void queryAnnotations(TransformedAnnotationsBuildItem transformedAnnotations, BuildProducer<MyBuildItem> myBuildItem) {
   ClassInfo myClazz = ...;
   if (transformedAnnotations.getAnnotations(myClazz).isEmpty()) { (1)
     myBuildItem.produce(new MyBuildItem());
   }
}
1 TransformedAnnotationsBuildItem.getAnnotations() は、変換された可能性のあるアノテーションのセットを返します。

5. ユースケース - Bean、オブザーバー、インジェクションポイントの検査

5.1. 解決策1. BeanDiscoveryFinishedBuildItem

BeanDiscoveryFinishedBuildItem のコンシューマーは、アプリケーションに登録されているすべてのクラスベースの Bean、オブザーバー、およびインジェクションポイントを簡単に検査できます。ただし、このビルドアイテムは合成コンポーネントが登録される に作成されるため、合成 Bean とオブザーバーは 含まれません

Additionally, the bean resolver returned from BeanDiscoveryFinishedBuildItem#getBeanResolver() can be used to apply the type-safe resolution rules, e.g. to find out whether there is a bean that would satisfy certain combination of required type and qualifiers.

BeanDiscoveryFinishedBuildItem の例
@BuildStep
void doSomethingWithNamedBeans(BeanDiscoveryFinishedBuildItem beanDiscovery, BuildProducer<NamedBeansBuildItem> namedBeans) {
   List<BeanInfo> namedBeans = beanDiscovery.beanStream().withName().collect(toList())); (1)
   namedBeans.produce(new NamedBeansBuildItem(namedBeans));
}
1 結果のリストに @Named 合成 Bean は含まれません。

5.2. 解決策2 : SynthesisFinishedBuildItem

SynthesisFinishedBuildItem のコンシューマーは、アプリケーションに登録されているすべての Bean、オブザーバー、およびインジェクションポイントを簡単に検査できます。このビルドアイテムは合成コンポーネントが登録された に作成されるため、合成 Bean とオブザーバーも 含まれます

Additionally, the bean resolver returned from SynthesisFinishedBuildItem#getBeanResolver() can be used to apply the type-safe resolution rules, e.g. to find out whether there is a bean that would satisfy certain combination of required type and qualifiers.

SynthesisFinishedBuildItem の例
@BuildStep
void doSomethingWithNamedBeans(SynthesisFinishedBuildItem synthesisFinished, BuildProducer<NamedBeansBuildItem> namedBeans) {
   List<BeanInfo> namedBeans = synthesisFinished.beanStream().withName().collect(toList())); (1)
   namedBeans.produce(new NamedBeansBuildItem(namedBeans));
}
1 結果のリストには、@Named 合成 Bean が含まれます。

6. ユースケース - 合成 Bean の必要性

ときには、合成 Bean を登録できると便利な場合もあります。合成 Bean の Bean 属性は、Java クラス、メソッド、またはフィールドから派生したものではありません。代わりに、すべての属性は拡張機能によって定義されます。そうするために、通常の CDI では AfterBeanDiscovery.addBean() メソッドを使用できます。

解決策: 合成 Bean を登録する必要がある場合は、SyntheticBeanBuildItem を使用します。

SyntheticBeanBuildItem の例 1
@BuildStep
SyntheticBeanBuildItem syntheticBean() {
   return SyntheticBeanBuildItem.configure(String.class)
             .qualifiers(new MyQualifierLiteral())
             .creator(mc -> mc.returnValue(mc.load("foo"))) (1)
             .done();
}
1 javax.enterprise.context.spi.Contextual#create(CreationalContext<T>) 実装の培土コードを生成します。

Bean Configurator の出力は、バイトコードとして記録されます。したがって、実行時に合成 Bean インスタンスを作成する方法にはいくつかの制限があります。以下が可能です。

  1. Contextual#create(CreationalContext<T>) メソッドのバイトコードを、ExtendedBeanConfigurator.creator(Consumer<MethodCreator>) を介して直接生成します。

  2. ExtendedBeanConfigurator#creator(Class<? extends BeanCreator<U>>) を介して io.quarkus.arc.BeanCreator 実装クラスを渡し、可能であれば ExtendedBeanConfigurator#param() を介していくつかのパラメーターを指定します。

  3. @Recorder メソッド から返されたプロキシー経由でランタイムインスタンスを生成し、それを ExtendedBeanConfigurator#runtimeValue(RuntimeValue<?>) または ExtendedBeanConfigurator#supplier(Supplier<?>) 経由で設定します。

SyntheticBeanBuildItem の例 2
@BuildStep
@Record(STATIC_INIT) (1)
SyntheticBeanBuildItem syntheticBean(TestRecorder recorder) {
   return SyntheticBeanBuildItem.configure(Foo.class).scope(Singleton.class)
                .runtimeValue(recorder.createFoo()) (2)
                .done();
}
1 デフォルトでは、合成 Bean は STATIC_INIT の間に初期化されます。
2 Bean インスタンスは、レコーダーメソッドから返される値によって提供されます。

RUNTIME_INIT の間に初期化される合成 Bean をマークできます。STATIC_INITRUNTIME_INIT の違いの詳細については、Three Phases of Bootstrap and Quarkus Philosophy を参照してください。

RUNTIME_INIT SyntheticBeanBuildItem の例
@BuildStep
@Record(RUNTIME_INIT) (1)
SyntheticBeanBuildItem syntheticBean(TestRecorder recorder) {
   return SyntheticBeanBuildItem.configure(Foo.class).scope(Singleton.class)
                .setRuntimeInit() (2)
                .runtimeValue(recorder.createFoo())
                .done();
}
1 レコーダーは、ExecutionTime.RUNTIME_INIT フェーズで実行する必要があります。
2 Bean インスタンスは、RUNTIME_INIT の間に初期化されます。

RUNTIME_INIT の間に初期化された合成 Bean は、STATIC_INIT の間にアクセスしてはいけません。runtime-init 合成 Bean にアクセスする RUNTIME_INIT ビルドステップは、SyntheticBeansRuntimeInitBuildItem を消費します。

@BuildStep
@Record(RUNTIME_INIT)
@Consume(SyntheticBeansRuntimeInitBuildItem.class) (1)
void accessFoo(TestRecorder recorder) {
   recorder.foo(); (2)
}
1 このビルドステップは、syntheticBean() の完了後に実行する必要があります。
2 このレコーダーメソッドでは Foo Bean インスタンスが呼び出されるため、必ずすべての合成 Bean が初期化された後にビルドステップが実行されることを確認する必要があります。
BeanRegistrationPhaseBuildItem を使用して合成 Bean を登録することもできます。ただし、エクステンション作成者においては、Quarkus にとってより慣用的な SyntheticBeanBuildItem を使用することをお勧めします。

7. ユースケース - 合成オブザーバー

synthetic beans と同様に、合成オブザーバーメソッドの属性は Java メソッドから派生しません。代わりに、すべての属性がエクステンションによって定義されます。

解決策: 合成オブザーバーを登録する必要がある場合は、ObserverRegistrationPhaseBuildItem を使用します。

ObserverRegistrationPhaseBuildItem を消費するビルドステップでは、常に ObserverConfiguratorBuildItem を生成するか、少なくともこのビルドアイテムに BuildProducer を 挿入する必要があります。でなければ、無視されるか、間違ったタイミングで処理される可能性があります (例: 正しい CDI ブートストラップフェーズの後)。
ObserverRegistrationPhaseBuildItem の例
@BuildStep
void syntheticObserver(ObserverRegistrationPhaseBuildItem observerRegistrationPhase,
            BuildProducer<MyBuildItem> myBuildItem,
            BuildProducer<ObserverConfiguratorBuildItem> observerConfigurationRegistry) {
   observerConfigurationRegistry.produce(new ObserverConfiguratorBuildItem(observerRegistrationPhase.getContext()
       .configure()
       .beanClass(DotName.createSimple(MyBuildStep.class.getName()))
       .observedType(String.class)
       .notify(mc -> {
           // do some gizmo bytecode generation...
       })));
   myBuildItem.produce(new MyBuildItem());
}

ObserverConfigurator の出力はバイトコードとして記録されます。したがって、実行時に合成オブザーバーを呼び出す方法にはいくつかの制限があります。現時点では、メソッド本体のバイトコードを直接生成する必要があります。

8. ユースケース - 生成された Bean クラスがある

問題ありません。Bean クラスのバイトコードを手動で生成し、その後に GeneratedClassBuildItem ではなく GeneratedBeanBuildItem を生成してください。

GeneratedBeanBuildItem の例
@BuildStep
void generatedBean(BuildProducer<GeneratedBeanBuildItem> generatedBeans) {
    ClassOutput beansClassOutput = new GeneratedBeanGizmoAdaptor(generatedBeans); (1)
    ClassCreator beanClassCreator = ClassCreator.builder().classOutput(beansClassOutput)
                .className("org.acme.MyBean")
                .build();
    beanClassCreator.addAnnotation(Singleton.class);
    beanClassCreator.close(); (2)
}
1 io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor を使用すると、Gizmo コンストラクトから GeneratedBeanBuildItem を簡単に作成できます。
2 結果の Bean クラスは、次のようになります: public class @Singleton MyBean { }

9. ユースケース - デプロイメントを検証する必要がある

エクステンションは、Bean、オブザーバー、およびインジェクションポイントを検査し、さらに追加の検証を実行して、何か問題がある場合はビルドを失敗にする必要があります。

解決策: エクステンションがデプロイメントを検証する必要がある場合、ValidationPhaseBuildItem を使用します。

ValidationPhaseBuildItem を消費するビルドステップでは、常に ValidationErrorBuildItem を生成するか、少なくともこのビルドアイテムに BuildProducer を 挿入する必要があります。でなければ、無視されるか、間違ったタイミングで処理される可能性があります (例: 正しい CDI ブートストラップフェーズの後)。
@BuildStep
void validate(ValidationPhaseBuildItem validationPhase,
            BuildProducer<MyBuildItem> myBuildItem,
            BuildProducer<ValidationErrorBuildItem> errors) {
   if (someCondition) {
     errors.produce(new ValidationErrorBuildItem(new IllegalStateException()));
     myBuildItem.produce(new MyBuildItem());
   }
}
ValidationPhaseBuildItem.getContext().beans() メソッドから返される便利な BeanStream を使用して、登録されているすべての Bean を簡単にフィルタリングできます。

10. ユースケース - カスタム CDI コンテキストの登録

時々、エクステンションは組み込みCDI コンテキストのセットを拡張する必要があります。

解決策: カスタムコンテキストを登録する必要がある場合は、ContextRegistrationPhaseBuildItem を使用します。

ContextRegistrationPhaseBuildItem を消費するビルドステップでは、常に ContextConfiguratorBuildItem を生成するか、少なくともこのビルドアイテムに `BuildProducer`を 挿入する必要があります。でなければ、無視されるか、間違ったタイミングで処理される可能性があります (例: 正しい CDI ブートストラップフェーズの後)。

ContextRegistrationPhaseBuildItem の例

@BuildStep
ContextConfiguratorBuildItem registerContext(ContextRegistrationPhaseBuildItem phase) {
      return new ContextConfiguratorBuildItem(phase.getContext().configure(TransactionScoped.class).normal().contextClass(TransactionContext.class));
}

さらに、ContextRegistrationPhaseBuildItem を介してカスタム CDI コンテキストを登録する各エクステンションは、Bean 定義アノテーションのセットにカスタムスコープアノテーション名を提供するために、CustomScopeBuildItem も生成する必要があります。

CustomScopeBuildItem の例

@BuildStep
CustomScopeBuildItem customScope() {
   return new CustomScopeBuildItem(DotName.createSimple(TransactionScoped.class.getName()));
}

10.1. アプリケーションで使用されているすべてのスコープを知る必要がある場合はどうなりますか?

ソリューション: ビルドステップで CustomScopeAnnotationsBuildItem を挿入し、 CustomScopeAnnotationsBuildItem.isScopeDeclaredOn() などの便利なメソッドを使用できます。

11. ユースケース - 追加のインターセプターバインディング

まれに、インターセプターバインディングとし て @javax.interceptor.InterceptorBinding でアノテーションが付けられていない既存のアノテーションをプログラムで登録すると便利な場合があります。これは、CDI が BeforeBeanDiscovery#addInterceptorBinding() で達成するものと似ています。これを行うには、InterceptorBindingRegistrarBuildItem を使用します。

InterceptorBindingRegistrarBuildItem の例
@BuildStep
InterceptorBindingRegistrarBuildItem addInterceptorBindings() {
    return new InterceptorBindingRegistrarBuildItem(new InterceptorBindingRegistrar() {
        @Override
        public List<InterceptorBinding> getAdditionalBindings() {
            return List.of(InterceptorBinding.of(NotAnInterceptorBinding.class));
        }
    });
}

12. 使用例 - 追加の修飾子

時には、 @javax.inject.Qualifier でアノテーションされていない既存のアノテーションをCDI修飾子として登録しておくと便利かもしれません。これは CDI が BeforeBeanDiscovery#addQualifier() を通して実現していることに似ています。ここでは QualifierRegistrarBuildItem を使ってそれを実現しようとしています。

QualifierRegistrarBuildItem の例
@BuildStep
QualifierRegistrarBuildItem addQualifiers() {
    return new QualifierRegistrarBuildItem(new QualifierRegistrar() {
        @Override
        public Map<DotName, Set<String>> getAdditionalQualifiers() {
            return Collections.singletonMap(DotName.createSimple(NotAQualifier.class.getName()),
                                        Collections.emptySet());
        }
    });
}

13. ユースケース - インジェクションポイントの変換

プログラムでインジェクションポイントの修飾子を変更できると便利な場合があります。それは、InjectionPointTransformerBuildItem で実行できます。次のサンプルは、修飾子 MyQualifier を含むタイプ Foo のインジェクションポイント変換を適用する方法を示しています。

InjectionPointTransformerBuildItem の例
@BuildStep
InjectionPointTransformerBuildItem transformer() {
    return new InjectionPointTransformerBuildItem(new InjectionPointsTransformer() {

        public boolean appliesTo(Type requiredType) {
            return requiredType.name().equals(DotName.createSimple(Foo.class.getName()));
        }

        public void transform(TransformationContext context) {
            if (context.getQualifiers().stream()
                    .anyMatch(a -> a.name().equals(DotName.createSimple(MyQualifier.class.getName())))) {
                context.transform()
                        .removeAll()
                        .add(DotName.createSimple(MyOtherQualifier.class.getName()))
                        .done();
            }
        }
    });
}
理論的には、AnnotationsTransformer を使用して同じ目標を達成できます。ただし、次の多少の違いがあるため、このタスクには InjectionPointsTransformer の方が適しています。その違いとは次のとおりです。(1) アノテーショントランスフォーマーは Bean 検出中にすべてのクラスに適用されますが、InjectionPointsTransformer は Bean 検出後に検出されたインジェクションポイントにのみ適用されます。(2) InjectionPointsTransformer を使用すると、さまざまなタイプのインジェクションポイント (フィールド、初期化メソッドのパラメーターなど) を処理する必要がありません。

14. ユースケース - リソースアノテーションとインジェクション

ResourceAnnotationBuildItem を使用して、Jakarta EE リソースなどの非 CDI インジェクションポイントを解決できるリソースアノテーションを指定できます。インテグレーターは、対応する io.quarkus.arc.ResourceReferenceProvider サービスプロバイダー実装も提供する必要があります。

ResourceAnnotationBuildItem の例
@BuildStep
void setupResourceInjection(BuildProducer<ResourceAnnotationBuildItem> resourceAnnotations, BuildProducer<GeneratedResourceBuildItem> resources) {
    resources.produce(new GeneratedResourceBuildItem("META-INF/services/io.quarkus.arc.ResourceReferenceProvider",
        MyResourceReferenceProvider.class.getName().getBytes()));
    resourceAnnotations.produce(new ResourceAnnotationBuildItem(DotName.createSimple(MyAnnotation.class.getName())));
}

15. 利用可能なビルドタイムメタデータ

BuildExtension.BuildContext で動作する上記のエクステンションはいずれも、ビルドタイムに生成される特定のビルドタイムメタデータを利用することができます。 io.quarkus.arc.processor.BuildExtension.Key にある組込キーは以下の通りです。

ANNOTATION_STORE

アノテーショントランスフォーマーを適用した後は、すべての`AnnotationTarget`アノテーションに関する情報を保持する AnnotationStore が含まれます

INJECTION_POINTS

すべてのインジェクションポイントを含む Collection<InjectionPointInfo>

BEANS

すべての Bean を含む Collection<BeanInfo>

REMOVED_BEANS

削除されたすべての Bean を含む Collection<BeanInfo>。詳細については Removing unused beans を参照してください。

OBSERVERS

すべてのオブザーバーを含む Collection<ObserverInfo>

SCOPES

カスタムスコープも含め、すべてのスコープを含む Collection<ScopeInfo>

QUALIFIERS

すべての修飾子を含む Map<DotName, ClassInfo>

INTERCEPTOR_BINDINGS

すべてのインターセプターバインディングを含む Map<DotName, ClassInfo>

STEREOTYPES

すべてのステレオタイプを含む Map<DotName, StereotypeInfo>

これらのメタデータを取得するには、そのキーのエクステンションコンテキストオブジェクトをクエリするだけ可能です。これらのメタデータはビルドが進むにつれて利用可能になることに注意してください。エクステンションがまだ生成されていないメタデータを取得しようとすると、 null が返されます。どのエクステンションがどのメタデータにアクセスできるかをまとめてみました。

AnnotationsTransformer

ブートストラップのどのフェーズでもいつでも使えるので、メタデータに頼るべきではありません。

ContextRegistrar

ANNOTATION_STORE , QUALIFIERS , INTERCEPTOR_BINDINGS . STEREOTYPES にアクセスできます。

InjectionPointsTransformer

ANNOTATION_STORE , QUALIFIERS , INTERCEPTOR_BINDINGS . STEREOTYPES にアクセスできます。

ObserverTransformer

ANNOTATION_STORE , QUALIFIERS , INTERCEPTOR_BINDINGS . STEREOTYPES にアクセスできます。

BeanRegistrar

ANNOTATION_STORE, QUALIFIERS, INTERCEPTOR_BINDINGS, STEREOTYPES, BEANS (クラスベースBeanのみ), OBSERVERS (クラスベースobserverのみ), INJECTION_POINTS にアクセスできます。

ObserverRegistrar

ANNOTATION_STORE , QUALIFIERS , INTERCEPTOR_BINDINGS , STEREOTYPES , BEANS , OBSERVERS (クラスベースのオブザーバーのみ), INJECTION_POINTS にアクセス可能です。

BeanDeploymentValidator

すべてのビルドメタデータにアクセスできます