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

它仅在生产者的创建方法中具有方法签名中的预期类型时起作用:

public class TestProducer {

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

现在,该字符串的注入正确,但是我也无法从生产者方法中生成整数。但这正是我要避免的,因为生产者本身应该是完全通用的。

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

有帮助吗?

解决方案

所有CDI文档都清楚地表明CDI确实 typesafe 依赖注射 - 它是CDI的崇高特性。恕我直言,您要做的就是CDI试图避免的事情。您希望容器铸造 Object 对于每种类型,CDI都无法正常工作。

注射点 stringValueintegerValue 只能收到一个豆子 java.lang.Stringjava.lang.Integer 在其清单中 豆类类型 分别。 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 条件确实决定使用其他条件以外的其他条件来确定注射点的类型,我建议您自己做“肮脏的工作”:将返回值注入 Object- 注射点,并手动进行演员表:

@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的这一方面来支持:)

其他提示

生产者 Object 无论如何都很奇怪。我不确定规格是否禁止这是一个错误,但我认为您可以进行一些聪明的解决方法:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

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

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

您的初始化器方法将寻找具有API类型字符串和整数的托管BEAN,但是您的生产者方法BEAN仅具有API类型(如果是生产者方法,返回类型)对象。

因此,您只能在初始化器方法中使用对象注入字段,然后区分接收器的主体的类型,或者简单地包装它们和可以返回字符串或INT的实际类型中的生产者方法(但是我避免了仿制药)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top