7.3. あいまいな依存関係または満たされていない依存関係

コンテナーが 1 つの Bean への注入を解決できない場合、依存関係があいまいとなります。

コンテナーがいずれの Bean に対しても注入の解決をできない場合、依存関係が満たされなくなります。

コンテナーは以下の手順を踏み、依存関係の解決をはかります。

  1. インジェクションポイントの Bean 型を実装する全 Bean にある修飾子アノテーションを解決します。
  2. 無効となっている Bean をフィルタリングします。無効な Bean とは、明示的に有効化されていない @Alternative Bean のことです。

依存関係があいまいな場合、あるいは満たされない場合は、コンテナーはデプロイメントを中断して例外を発生させます。

あいまいな依存関係を修正するには、「修飾子を使用したあいまいなインジェクションの解決」を参照してください。

7.3.1. 修飾子

修飾子は、コンテナーが複数の Bean を解決できるときにあいまいな依存関係を回避するために使用されるアノテーションであり、インジェクションポイントに含められます。インジェクションポイントで宣言された修飾子は、同じ修飾子を宣言する有効な Bean セットを提供します。

修飾子は、以下の例で示されたように Retention と Target を使用して宣言する必要があります。

例: @Synchronous 修飾子と @Asynchronous 修飾子の定義

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {}

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Asynchronous {}

例: @Synchronous 修飾子と @Asynchronous 修飾子の使用

@Synchronous
public class SynchronousPaymentProcessor implements PaymentProcessor {
   public void process(Payment payment) { ... }
}

@Asynchronous
public class AsynchronousPaymentProcessor implements PaymentProcessor {
   public void process(Payment payment) { ... }
}
'@Any'

Bean またはインジェクションポイントにより修飾子が明示的に宣言されない場合、コンテナーにより修飾子は @Default と見なされます。場合によっては、修飾子を指定せずにインジェクションポイントを宣言する必要があります。この場合も修飾子が存在します。すべての Bean には修飾子 @Any が含まれます。したがって、インジェクションポイントで @Any を明示的に指定することにより、インジェクションが可能な Bean を制限せずにデフォルトの修飾子を抑制できます。

これは、特定の bean タイプを持つすべての Bean に対して繰り返し処理を行う場合に特に役に立ちます。

import javax.enterprise.inject.Instance;
...

@Inject

void initServices(@Any Instance<Service> services) {

   for (Service service: services) {

      service.init();

   }

}

各 Bean は、@Any 修飾子を明示的に宣言しない場合でもこの修飾子を持ちます。

各イベントも、@Any 修飾子が明示的に宣言されずに発生した場合でもこの修飾子を持ちます。

@Inject @Any Event<User> anyUserEvent;

@Any 修飾子により、インジェクションポイントが特定の Bean タイプのすべての Bean またはイベントを参照できます。

@Inject @Delegate @Any Logger logger;

7.3.2. 修飾子を使用したあいまいなインジェクションの解決

修飾子を使用してあいまいなインジェクションを解決できます。あいまいなインジェクションは「あいまいな依存関係または満たされていない依存関係」をお読みください。

以下の例はあいまいであり、Welcome の 2 つの実装 (翻訳を行う 1 つと翻訳を行わないもう 1 つ) を含みます。翻訳を行う Welcome を使用するには、インジェクションを指定する必要があります。

例: あいまいなインジェクション

public class Greeter {
  private Welcome welcome;

  @Inject
  void init(Welcome welcome) {
    this.welcome = welcome;
  }
  ...
}

修飾子を使用したあいまいなインジェクションの解決
  1. あいまいなインジェクションを解決するには、@Translating という名前の修飾子アノテーションを作成します。

    @Qualifier
    @Retention(RUNTIME)
    @Target({TYPE,METHOD,FIELD,PARAMETERS})
    public @interface Translating{}
  2. 翻訳を行う Welcome@Translating アノテーションを付けます。

    @Translating
    public class TranslatingWelcome extends Welcome {
        @Inject Translator translator;
        public String buildPhrase(String city) {
            return translator.translate("Welcome to " + city + "!");
        }
        ...
    }
  3. インジェクションで翻訳を行う Welcome を要求します。ファクトリーメソッドパターンの場合と同様に、修飾された実装を明示的に要求する必要があります。あいまいさはインジェクションポイントで解決されます。

    public class Greeter {
      private Welcome welcome;
      @Inject
      void init(@Translating Welcome welcome) {
        this.welcome = welcome;
      }
      public void welcomeVisitors() {
        System.out.println(welcome.buildPhrase("San Francisco"));
      }
    }