Domanda

Ho un metodo produttore CDI, che - a seconda di alcune condizioni che non interessano a questo esempio - crea oggetti di tipo diverso:

public class TestProducer {

  @Produces @TestQualifier
  public Object create(InjectionPoint ip) {
    if(something) {
      return "a String";
    } else {
      return Integer.valueOf(42);
    }
  }

, ma quando si utilizza questo produttore, ho sempre arrivare un errore nella situazione followin:

@Named("test")
public class TestComponent {
   ...
   @Inject public void setA(@TestQualifier String stringValue) {
   ...
   @Inject public void setB(@TestQualifier Integer integerValue) {

Funziona solo quando il metodo del produttore creare ha il tipo previsto nella firma del metodo:

public class TestProducer {

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

Ora la stringa ottenere iniettato correttamente, ma non ho modo di generare anche un numero intero da metodo produttore. Ma questo è esattamente quello che voglio evitare, dal momento che il produttore stesso dovrebbe essere del tutto generico.

sto facendo qualcosa di sbagliato o non c'è un modo per ottenere il comportamento desiderato?

È stato utile?

Soluzione

documentazione Tutto CDI chiarisce che CDI typesafe iniezione di dipendenza - ed è una proprietà esaltato di CDI. IMHO, ciò che si sta cercando di fare è proprio quello CDI cerca di evitare. Si desidera che il contenitore per getto Object di ogni tipo e CDI non funziona in questo modo.

I punti iniezioni stringValue e integerValue può ricevere solo un fagiolo che ha java.lang.String e java.lang.Integer nella sua lista di tipi di fagioli rispettivamente. java.lang.Object non soddisfa tale criterio.

Ho due suggerimenti. In primo luogo, dal momento che si dispone di due o più punti di iniezione di tipo diverso, creare due o più produttori metodi per che i tipi:

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
    }
  }
// ...

Funziona se la condizione something è solo quello di verificare il tipo di punto di iniezione (quello che sto scommesse è il caso).

Tuttavia, se la condizione something fa decidere il tipo utilizzando altri criteri rispetto al tipo del punto di iniezione, mi piacerebbe suggerimento per fare il "lavoro sporco" voi stessi: Iniettare il valore restituito in un punto di iniezione Object tipizzato e lo fa il cast manualmente:

@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;

Il punto principale è che, a differenza di alcuni altri quadri DI, CDI non funziona contro il sistema di tipo Java - al contrario, utilizza pesantemente esso. Non cercare di lottare contro di esso, ma utilizzare questo aspetto della CDI a tuo favore:)

Altri suggerimenti

Un produttore per Object è strano comunque. Non sono sicuro se questo è vietato dalle specifiche, o si tratta di un bug, ma credo che si può fare qualche soluzione intelligente:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

E poi iniettare un ValueHolder<String> e ValueHolder<Integer>

I suoi oggetti possibile creare generici con CDI produce così:

  // 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();
      }

    }

Opere su di saldatura 2.2.0. Penso che funziona su alcune versioni precedenti pure.

I tuoi metodi di inizializzazione andrà a cercare un bean gestito con i tipi di API String e Integer, ma il metodo di fagioli produttore ha solo tipo di API (in caso di metodo produttore, tipo di ritorno) oggetto.

Si può quindi utilizzare solo oggetto nel initializer metodo campi iniettato e quindi discriminare tra i tipi int il corpo del ricevente, o semplicemente li e il metodo produttore in un tipo effettivo che può restituire stringhe o Int (ma io avvolgere' d evitare i farmaci generici)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top