Общий метод производителя CDI не работает, как и ожидалось

StackOverflow https://stackoverflow.com/questions/4303514

  •  29-09-2019
  •  | 
  •  

Вопрос

У меня есть метод продюсера 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 делает Типов Инъекция зависимости - и это возвышенное свойство CDI. ИМХО, то, что вы пытаетесь сделать, это то, что CDI пытается избежать. Вы хотите, чтобы контейнер разыграл Object К каждому типу и CDI не работает так.

Инъекции указывают stringValue и integerValue может получить только боб, которая имеет java.lang.String и java.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-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 в вашу пользу :)

Другие советы

Производитель для 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, но ваш метод производителя имеет только тип API (в случае метода производителя, возврата типа) объект.

Поэтому вы можете использовать только объект в полях INATIVER INATIVER, а затем дискриминировать типы int тело ресивера или просто обернуть их и метод производителя в фактическом типе, который может возвращать строки или INT (но я бы избегал Дженерики)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top