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) {

现在 String get 已正确注入,但我无法从生产者方法中生成一个整数。但这正是我想要避免的,因为生产者本身应该是完全通用的。

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

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 不能以这种方式工作。

注入点stringValue并且integerValue只能接收一个在其bean 类型列表中分别具有java.lang.String和的 bean 。不满足这个标准。java.lang.Integerjava.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-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 的这一方面对你有利:)

于 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 ,然后区分接收器主体中的类型,或者简单地将它们和生产者方法包装在可以返回 Strings 或 Int 的实际类型中(但我会避免泛型)

于 2011-01-08T14:30:49.903 回答