通用CDI生产者方法无法按预期工作

时间:2010-11-29 12:04:27

标签: java java-ee cdi

我有一个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) {

现在正确地注入了String get,但我无法从producer方法生成一个整数。但这正是我想要避免的,因为制作人本身应该是完全通用的。

我做错了什么或者没有办法实现我想要的行为?

4 个答案:

答案 0 :(得分:4)

Object的制作人无论如何都很奇怪。我不确定这是否被规范禁止,或者它是一个错误,但我认为你可以做一些聪明的解决方法:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

然后注入ValueHolder<String>ValueHolder<Integer>

答案 1 :(得分:4)

所有CDI文档都清楚地表明CDI执行 typesafe 依赖注入 - 它是CDI的高级属性。恕我直言,你要做的就是CDI试图避免的。您希望容器将Object强制转换为每种类型,并且CDI不会以这种方式工作。

注入点stringValueintegerValue只能分别接收bean types列表中java.lang.Stringjava.lang.Integer的bean。 java.lang.Object不符合此标准。

我有两个建议。首先,由于您有两个或更多不同类型的注入点,因此为这些类型创建两个或更多个生成器方法:

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条件使用除注入点类型之外的其他条件确定类型,我建议自己执行“脏工作”:将返回值注入{{1键入注入点并手动执行转换:

Object

重点在于,与其他一些DI框架不同,CDI不会对Java类型系统起作用 - 相反,它大量使用它。不要试图反对它,但使用CDI的这方面对你有利:)

答案 2 :(得分:2)

可能使用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。 我认为这也适用于以前的某些版本。

答案 3 :(得分:1)

您的初始化方法将查找具有API类型String和Integer的托管bean,但您的生产者方法bean仅具有API类型(在生产者方法,返回类型的情况下)对象。

因此,您只能在初始化方法注入的字段中使用Object,然后区分接收者主体中的类型,或者只是将它们和生成器方法包装在可以返回字符串或Int的实际类型中(但是我' d避免使用泛型)