Question

J'ai une méthode de production CDI qui - selon certaines conditions ne sont pas pertinentes à cet exemple - crée des objets de différents types:

public class TestProducer {

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

mais lorsque vous utilisez ce producteur, je reçois toujours une erreur dans la situation followin:

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

Il ne fonctionne que lorsque la méthode create du producteur a le type prévu dans la signature de la méthode:

public class TestProducer {

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

Maintenant, la chaîne get injecté correctement, mais je n'ai aucun moyen de générer également un nombre entier de la méthode de production. Mais c'est exactement ce que je veux éviter, puisque le producteur lui-même doit être complètement générique.

Ai-je fait quelque chose de mal ou est-il pas moyen d'obtenir le comportement que je veux?

Était-ce utile?

La solution

Tous les documents CDI, il est clair que le CDI fait typesafe injection de dépendance - et il est une propriété élevé de CDI. À mon humble avis, ce que vous essayez de faire est tout ce que CDI essaie d'éviter. Vous voulez que le récipient moulé Object à chaque type et CDI ne fonctionne pas de cette façon.

Les injections de points stringValue et integerValue ne peut recevoir un haricot qui a java.lang.String et java.lang.Integer dans sa liste types de haricots respectivement. java.lang.Object ne satisfait pas à ce critère.

J'ai deux suggestions. Tout d'abord, puisque vous avez deux ou plusieurs points d'injection de différents types, créez deux ou plusieurs méthodes pour la production que les types:

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

Il fonctionne si la condition de something est juste pour vérifier le type de point d'injection (ce que je fais le pari est le cas).

Cependant, si la condition de something ne décide du type en utilisant d'autres critères que le type du point d'injection, je suggestion de faire vous-même « sale boulot »: Injecter la valeur retournée dans un point d'injection typé Object et fait la coulée manuellement:

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

Le point principal est que, contrairement à d'autres cadres de DI, le CDI ne fonctionne pas contre le système de type Java - au contraire, il utilise beaucoup il. Ne pas essayer de lutter contre elle, mais utiliser cet aspect du CDI en votre faveur:)

Autres conseils

Un producteur pour Object est étrange de toute façon. Je ne sais pas si cela est interdit par la spécification, ou il est un bug, mais je pense que vous pouvez faire une solution intelligente:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

Et puis Injecter ValueHolder<String> et ValueHolder<Integer>

Il est possible de créer des objets génériques avec CDI produit comme ça:

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

    }

Travaux sur la soudure 2.2.0. Je pense que les travaux sur certaines versions précédentes ainsi.

Vos méthodes de initialiseur vont chercher un bean géré avec des types d'API chaîne et entier, mais votre grain de méthode de production a seul type API (en cas de la méthode de production, type de retour) Objet.

Vous pouvez donc utiliser seul objet dans votre initialiseur méthode injectée champs et discriminante entre les types int le corps du récepteur, ou tout simplement les envelopper et la méthode de production dans un type réel qui peut renvoyer des chaînes ou Int (mais je » d éviter les génériques)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top