I have read about the @Produces annotation in CDI, but I don't understand its usage.
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(); }
}
taken from: http://www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-
How does the container know to call a producer method? If I inject an EntityManager, how does the container call the @produces EntityManager? And how would a getLogger producer method get called?
I also don't see the reason to go through all of the trouble.
Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class. @Inject is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.
Java EE CDI introduced a concept called Producer. Producers may be used to create - or produce - bean instances to be consumed by an application. Producers are also able to provide specific interface implementations according to the consumer needs so they are a valid way to support polymorphism in a CDI application.
4.1. The @Inject annotation lets us define an injection point that is injected during bean instantiation. Injection can occur via three different mechanisms. Bean constructor parameter injection: public class Checkout { private final ShoppingCart cart; @Inject.
A producer method generates an object that can then be injected. Typically, you use producer methods in the following situations: When you want to inject an object that is not itself a bean. When the concrete type of the object to be injected may vary at runtime.
Section 3.3 of the CDI specification gives a pretty good high level overview of the use of the @Produces
annotation:
A producer method acts as a source of objects to be injected, where:
• the objects to be injected are not required to be instances of beans, or
• the concrete type of the objects to be injected may vary at runtime, or
• the objects require some custom initialization that is not performed by the bean constructor.
Let's say, for example, that you wanted to bridge between a Java EE managed component like an entity manager and other CDI components, you could utilize the @Produces
annotation. Another benefit being that you avoid having to duplicate @PersistenceContext
annotations throughout your data domain layer.
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; }
Another handy use is for getting around libraries that do not have CDI friendly beans (for example, no default constructors):
class SomeTPLClass { public SomeTPLClass(String id) { } } class SomeTPLClassProducer { @Produces public SomeTPLClass getInstance() { return new SomeTPLClass(""); } }
The Javadoc for produces also shows an interesting (but fairly rare case) of producing a named collection that can later on be injected into other managed beans (very 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; }
The container is responsible for processing all methods and fields marked with a @Produces annotation, and will normally do this when your application is deployed. The processed methods and fields will then be used as part of the injection point resolution for managed beans, as needed.
The example didn't quite work for me. What dit work was a minor tweak:
@Alternative class SomeTPLClass { public SomeTPLClass(String id) { } } class SomeTPLClassProducer { @Produces public SomeTPLClass getInstance() { return new SomeTPLClass(""); } }
So i had to add @Alternative on my class to get rid of the error that there were two options for @Default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With