代码之家  ›  专栏  ›  技术社区  ›  Christian Seifert

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

  •  4
  • Christian Seifert  · 技术社区  · 14 年前

    我有一个cdi-producer方法,它根据与本示例无关的某些条件创建不同类型的对象:

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

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

    我是在做错事还是没有办法达到我想要的行为?

    4 回复  |  直到 10 年前
        1
  •  4
  •   brandizzi    13 年前

    所有CDI文件都清楚地表明CDI确实 类型安全 依赖注入——它是CDI的一个高级属性。imho,你想做的就是CDI想要避免的。你想把容器浇铸起来 Object 对于每一种类型,CDI并不是这样工作的。

    注射点 stringValue integerValue 只能接收具有 java.lang.String java.lang.Integer 在它的列表中 bean types 分别。 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 条件只是检查注入点的类型(我打赌是这样的)。

    某物 条件确实使用注入点类型以外的其他条件来决定类型,我建议自己做“脏的工作”:将返回值注入 对象 -类型化注射点和手动铸造:

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

        2
  •  4
  •   Bozho    14 年前

    制片人 Object 反正很奇怪。我不确定规范是否禁止这样做,或者这是一个bug,但我认为您可以做一些巧妙的变通方法:

    public class ValueHolder<T> {
        private T value;
    
        public T getValue() {
            return value;
        }
    }
    

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

        3
  •  2
  •   Welyab Paula    10 年前

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

        4
  •  1
  •   covener    14 年前

    初始值设定项方法将查找API类型为string和integer的托管bean,但生成方方法bean仅具有API类型(对于生成方方法,返回类型)对象。

    因此,您只能在初始值设定项方法注入的字段中使用对象,然后区分接收程序主体中的int类型,或者简单地将它们包装为可以返回字符串或int的实际类型中的producer方法(但我将避免使用泛型)。

    推荐文章