4

この例に関係のないいくつかの条件に応じて、さまざまなタイプのオブジェクトを作成するCDIプロデューサーメソッドがあります。

public class TestProducer {

  @Produces @TestQualifier
  public Object create(InjectionPoint ip) {
    if(something) {
      return "a String";
    } else {
      return Integer.valueOf(42);
    }
  }

しかし、このプロデューサーを使用すると、次の状況で常にエラーが発生します。

@Named("test")
public class TestComponent {
   ...
   @Inject public void setA(@TestQualifier String stringValue) {
   ...
   @Inject public void setB(@TestQualifier Integer integerValue) {

これは、プロデューサーのcreateメソッドがメソッドシグネチャに期待されるタイプを持っている場合にのみ機能します。

public class TestProducer {

  @Produces @SpringBean
  public String create(InjectionPoint ip) {

これで文字列が正しく挿入されましたが、プロデューサーメソッドから整数を生成する方法もありません。しかし、プロデューサー自体は完全にジェネリックである必要があるため、これはまさに私が避けたいことです。

私は何か間違ったことをしているのですか、それとも私が望む行動を達成する方法がありませんか?

4

4 に答える 4

4

Objectとにかくプロデューサーはおかしい。これが仕様で禁止されているのか、それともバグなのかはわかりませんが、巧妙な回避策を講じることができると思います。

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

そしてValueHolder<String>ValueHolder<Integer>

于 2010-11-29T15:02:45.667 に答える
4

すべての CDI ドキュメントは、CDI がタイプセーフな依存性注入を行うことを明確にしています。これは CDI の優れた特性です。私見、あなたがやろうとしていることは、CDIが回避しようとしているものです。コンテナーを各型にキャストする必要がありますがObject、CDI はそのようには機能しません。

インジェクションは、 Bean タイプのリストにそれぞれとを持つ Bean のみをポイントstringValueし、受け取ることができます。この基準を満たしていません。integerValuejava.lang.Stringjava.lang.Integerjava.lang.Object

2つの提案があります。まず、異なるタイプの注入ポイントが 2 つ以上あるため、そのタイプのプロデューサー メソッドを 2 つ以上作成します。

public class TestProducer {

  @Produces @TestQualifier
  public String createString(InjectionPoint ip) {
    if(something) {
      return "a String";
    } else {
      // Some other value
    }
  }

  @Produces @TestQualifier
  public int createInt(InjectionPoint ip) {
    if(something) {
      return 42;
    } else {
      // Some other value
    }
  }
// ...

条件が注入ポイントのタイプを確認することだけであれば機能しsomethingます (私が賭けているのはその場合です)。

ただし、something条件が注入ポイントのタイプ以外の基準を使用してタイプを決定する場合は、「汚い仕事」を自分で行うことをお勧めします。戻り値をObject-typed 注入ポイントに注入し、手動でキャストします。

@Named("test")
public class TestComponent {
   ...
   @Inject public void setA(@TestQualifier Object value) {
       String stringValue = (String) value;

   ...
   @Inject public void setB(@TestQualifier Object value) {
       int intValue = (Integer) value;

要点は、他の DI フレームワークとは異なり、CDI は Java 型システムに対して機能しないということです。逆に、CDI は Java 型システムを頻繁に使用します。それと戦おうとしないで、CDI のこの側面を有利に利用してください :)

于 2011-07-06T21:25:45.813 に答える
3

CDI を使用して汎用オブジェクトを作成すると、次のように生成されます。

  // the wrapper class
    public class Wrapper<T> {
      public final T bean;
      public Wrapper(T bean){
        this.bean = bean;
      }
    }

    // the producer inside some class
    @Produces
    public <T> Wrapper<T> create(InjectionPoint p){
      // with parameter 'p', it is possible retrieve the class type of <T>, at runtime
    }


    // the bean example 1
    public class BeanA {
      public void doFoo(){
        // ...
      }
    }
    // the bean example 2
    public class BeanB {
      public void doBar(){
        // ...
      }
    }


    // the class that uses the produced beans
    public class SomeBean{

//// There on producer method, do you can retrieve the Class object of BeanA and BeanB, from type parameters of Wrapper.

      @Inject
      private Wrapper<BeanA> containerA;
      @Inject
      private Wrapper<BeanB> containerB;

      public void doSomeThing(){
         containerA.doFoo();
         containerB.doBar();
      }

    }

溶接 2.2.0 で動作します。一部の以前のバージョンでも機能すると思います。

于 2014-12-12T07:36:31.630 に答える
1

イニシャライザ メソッドは API タイプが String および Integer のマネージド Bean を探しますが、プロデューサー メソッド Bean は API タイプ (プロデューサー メソッドの場合は戻り値のタイプ) Object しかありません。

したがって、初期化メソッドに挿入されたフィールドで Object のみを使用して、レシーバーの本体の int 型を区別するか、単純にそれらとプロデューサー メソッドを、String または Int を返すことができる実際の型でラップすることができます (ただし、ジェネリック)

于 2011-01-08T14:30:49.903 に答える