Frage

Ich habe eine CDI Producer-Methode, die - abhängig von bestimmten Bedingungen nicht relevant für dieses Beispiel - Objekte verschiedenen Typen erstellt:

public class TestProducer {

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

aber wenn diese Hersteller mit, habe ich immer einen Fehler in der followin Situation bekommen:

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

Es funktioniert nur, wenn das Verfahren des Herstellers schafft, hat die erwartete Art in der Methodensignatur:

public class TestProducer {

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

Nun ist der String gets richtig injizierte, aber ich habe keine Möglichkeit, auch eine ganze Zahl aus der Producer-Methode zu erzeugen. Aber das ist genau das, was ich vermeiden will, da der Produzent selbst sein sollte vollständig generisch.

Bin ich etwas falsch zu machen oder gibt es keine Möglichkeit, das Verhalten ich will?

zu erreichen
War es hilfreich?

Lösung

Alle CDI-Dokumentation macht deutlich, dass CDI tut typsicher Dependency Injection - und es ist eine erhabene Eigenschaft von CDI. IMHO, was Sie zu tun versuchen, ist genau das, was CDI zu vermeiden versucht. Sie wollen den Behälter gegossen Object für jeden Typ und CDI funktioniert nicht auf diese Art und Weise.

Die Injektionen Punkte stringValue und integerValue kann nur eine Bohne erhalten, die java.lang.String und java.lang.Integer in seiner Liste der Bohnensorten sind. java.lang.Object dieses Kriterium nicht erfüllen.

Ich habe zwei Vorschläge. Erstens, da Sie zwei oder mehr Injektionspunkte verschiedenen Typen haben, erstellen Sie zwei oder mehr Erzeuger Methoden für diese Typen:

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

Es funktioniert, wenn der something Zustand gerade ist, die Art der Injektionsstelle zu überprüfen (was ich Wetten der Fall ist).

Wenn jedoch der something Zustand die Art nach anderen Kriterien als die Art der Injektionsstelle entscheidet, würde ich Vorschlag, die „schmutzige Arbeit“ selbst zu tun: inject des zurückgegebene Wert in einer Object typisierte Impfstelle und tue die Besetzung manuell:

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

Der wichtigste Punkt ist, dass, im Gegensatz zu einigen anderen DI-Frameworks, CDI funktioniert nicht gegen den Java-Typ-System - im Gegenteil, es es schwer verwendet. Versuchen Sie nicht, gegen sie zu kämpfen, aber diesen Aspekt der CDI zu Ihren Gunsten nutzen:)

Andere Tipps

Ein Hersteller für Object ist seltsam, irgendwie. Ich bin nicht sicher, ob dies durch die spec verboten ist, oder es ist ein Fehler, aber ich denke, man kann einige clevere Abhilfe machen:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

Und dann inject ein ValueHolder<String> und ValueHolder<Integer>

Es ist möglich, erstellen generische Objekte mit CDI produziert wie folgt aus:

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

    }

Arbeiten auf Schweiß 2.2.0. Ich denke, dass die Arbeiten auf einigen früheren Versionen auch.

Ihre initializer Methoden suchen nach einer verwalteten Bean mit API-Typen String und Integer, aber Ihre Producer-Methode Bohne hat nur API-Typen (im Fall des Erzeuger Methode Rückgabetyp) Objekts.

Sie können daher nur Objekt in Ihrer initializer Methode verwenden, um Felder injizierten und dann zu diskriminieren zwischen den Arten, den Körper des Empfängers int oder einfach wickeln sie und die Producer-Methode in einem tatsächlichen Typ, Strings oder Int zurückgeben kann (aber ich‘ vermeiden d die Generika)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top