web-dev-qa-db-fra.com

Veuillez expliquer l'annotation @Produces dans CDI

J'ai lu l'existence de l'annotation @Produces dans CDI, mais je ne comprends pas son utilisation.

public class Resources {

// Expose an entity manager using the resource producer pattern
@SuppressWarnings("unused")
@PersistenceContext
@Produces
private EntityManager em;                                        // 

@Produces
Logger getLogger(InjectionPoint ip) {                            // 
    String category = ip.getMember()
                        .getDeclaringClass()
                        .getName();
    return Logger.getLogger(category);
}

@Produces
FacesContext getFacesContext() {                                 // 
    return FacesContext.getCurrentInstance();
}

}

extrait de: http://www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-

Comment le conteneur sait-il appeler une méthode de production? Si j'injecte un EntityManager, comment le conteneur appelle-t-il @produces EntityManager? Et comment une méthode de producteur getLogger serait-elle appelée? 

Je ne vois pas non plus la raison de passer par tous les problèmes.

38
user798719

La section 3.3 de la spécification CDI donne une assez bonne vue d'ensemble de l'utilisation de l'annotation @Produces :

Une méthode de production sert de source d’objets à injecter, où:

• les objets à injecter ne doivent pas nécessairement être des exemples de haricots, ou
• le type concret des objets à injecter peut varier au moment de l'exécution, ou
• les objets nécessitent une initialisation personnalisée qui n'est pas effectuée par le constructeur de bean.

Supposons, par exemple, que vous souhaitiez créer un pont entre un composant géré Java EE tel qu'un gestionnaire d'entités et d'autres composants CDI, vous pouvez utiliser l'annotation @Produces. Un autre avantage est que vous évitez de dupliquer les annotations @PersistenceContext dans votre couche de domaine de données.

class A {
    @PersistenceContext       // This is a JPA annotation
    @Produces                 // This is a CDI 'hook'
    private EntityManager em; 
}

class B {
   @Inject                    // Now we can inject an entity manager
   private EntityManager em;
}

Une autre utilisation pratique est de contourner les bibliothèques qui n'ont pas de beans amical CDI (par exemple, aucun constructeur par défaut):

class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

La Javadoc for Prod montre également un cas intéressant (mais assez rare) de production d'une collection nommée qui peut ensuite être injectée dans d'autres beans gérés (très cool):

public class Shop { 
    @Produces @ApplicationScoped 
    @Catalog @Named("catalog") 
    private List<Product> products = new LinkedList<Product>(8);

    //...
}

public class OrderProcessor {
    @Inject
    @Catalog
    private List<Product> products;
}

Le conteneur est responsable du traitement de toutes les méthodes et de tous les champs marqués d'une annotation @Produces. Il le fait normalement lorsque votre application est déployée. Les méthodes et les champs traités seront ensuite utilisés dans le cadre de la résolution du point d'injection pour les beans gérés, si nécessaire.

64
Perception

L'exemple n'a pas fonctionné pour moi. Quel travail était un tweak mineur:

@Alternative
class SomeTPLClass {
    public SomeTPLClass(String id) {
    }
}

class SomeTPLClassProducer {
    @Produces
    public SomeTPLClass getInstance() {
        return new SomeTPLClass("");
    }
}

Donc, je devais ajouter @Alternative sur ma classe pour me débarrasser de l'erreur selon laquelle il y avait deux options pour @Default .

0
Hans