Please explain the @Produces annotation in CDI

JavaJakarta EeCdi

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser798719View Question on Stackoverflow
Solution 1 - JavaPerceptionView Answer on Stackoverflow
Solution 2 - JavaHansView Answer on Stackoverflow