はじめに
最近、Quarkusアプリケーションの開発中にCDI1関係でハマったので、その時の解決方法を書き残しておきます。
なおKotlin
でQuarkus
アプリケーションを開発している時に出くわした問題ですが、Quarkus
やKotlin
特有の話ではなく、CDIの仕様に基づく挙動のため、Jakarta EE
全般で同じようなことは起こり得ると思います。
Quarkus + CDI で UnsatisfiedResolutionException に出くわした
自作クラスAのインスタンスを、別の自作クラスBにコンストラクタインジェクションしようとするけれど、例外(UnsatisfiedResolutionException
)がスローされて起動できない状態になりました。
ちなみにクラスAとクラスBは別のプロジェクトに配置されていました。
クラス名は伏せますが、その時のスタックトレースは以下のとおりです。
ザックリいうと「インジェクションしようとしているBeanが見つからない」と言われています。
<====2025-03-18 21:34:30,234 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errorsUTING [20s]
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: jakarta.enterprise.inject.spi.DeploymentException: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type {インジェクションするクラスの完全修飾名} and qualifiers [@Default]
- injection target: parameter '{インジェクション先クラスの変数名}' of {インジェクション先クラスの完全修飾名} constructor
- declared on CLASS bean [types=[{インジェクション先クラスの完全修飾名}, java.lang.Object], qualifiers=[@Default, @Any], target={インジェクション先クラスの完全修飾名}]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1551)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:338)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:167)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:490)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733)
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
at io.quarkus.builder.BuildContext.run(BuildContext.java:256)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)
at java.base/java.lang.Thread.run(Thread.java:1583)
at org.jboss.threads.JBossThread.run(JBossThread.java:483)
Caused by: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type {インジェクションするクラスの完全修飾名} and qualifiers [@Default]
- injection target: parameter '{インジェクション先クラスの変数名}' of {インジェクション先クラスの完全修飾名} constructor
- declared on CLASS bean [types=[{インジェクション先クラスの完全修飾名}, java.lang.Object], qualifiers=[@Default, @Any], target={インジェクション先クラスの完全修飾名}]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:545)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:667)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:323)
... 11 more
原因と解決方法
結論から言うと、(だいぶ基礎的な部分の見落としですが、)インジェクションするクラスのプロジェクト内にbeans.xml
がなかったのが原因でした。
パスまで含めて言うとsrc/main/resources/META-INF/beans.xml
ですね。
基本的にQuarkus
では@ApplicationScoped
などのスコープアノテーションが付いていれば、beans.xml
がなくてもBeanとして扱ってくれるはずです。ただ今回のケースではプロジェクトが分かれていたこともあり、beans.xml
を置いて明示的にBeanアーカイブと示さないとBeanを見つけてもらえなかったようです。
なおbeans.xml
は空ファイルで問題ありませんでした。
beans.xml
が置かれていることが「このJARファイル(ないしプロジェクト)はBeanアーカイブである」ということを示すためのマーカーとしての意味を持つので、今回はただファイルを置いただけで解決したようです。
-
CDIについて簡単に触れておくと、DI(Dependency Injection: 依存性の注入)の仕様の一つで、
Context and Dependency Injection
の略です。通常のDIに対して色々と機能が増えており、たとえばコンテキスト(オブジェクトのライフサイクル)管理がその一例です。 ↩