What happens if we want to inject an object or type at runtime, dynamically? CDI allows us to do this with the concept of productions. Producer methods are the way to inject arbitrary objects into the container, which are not registered as beans through the annotations. Typically, this is the way to get dynamic behavior.
Let us suppose we have a payment system for checking credit worthiness with some financial service legal entity. It is a very simple credit model-you only need an account number - and we can define a contract for this service as a Java interface.
public interface CreditProcessor { public void check(String account); }
We will reuse the annotations from the standalone travel service example, @Premium
and @Economy
. We are given the business requirement for the economy as a high volume and high turnover, and the model leverages lots of promotional workers who act on behalf of the businesses to find and locate customers. There are a lot of dynamics and so it can be modeled as a production using the following HouseholdCredit
class:
public class HouseholdCredit {
private static AtomicInteger counter = new AtomicInteger(1000);
@Produces
@Economy
public CreditProcessor createCreditProcessor() {
return new StreetCreditProcessor("promoter"+counter.getAndIncrement());
}
public static class StreetCreditProcessor
implements CreditProcessor {
private final String workerId;
public StreetCreditProcessor(String workerId) {
this.workerId = workerId;
}
@Override
public void check(String account) {/*...*/}
@Override
public String toString() {
return "StreetCreditProcessor{" +
"workerId='" + workerId + ''' +
'}';
}
}
}
The key annotation is @javax.enterprise.inject
. Produces, which informs the CDI container that the application is responsible for creating a particular bean type. The @Produces
annotation designates a POJO application bean as producer of a CDI managed beans.
Do not confuse CDI's @Produces
with another Java EE 7 annotation @javax.ws.rs.Produces
, which is part of JAX-RS. See Chapter 8, RESTful Services JAX-RS 2.0.
The class HouseholdCredit
declares to CDI that it can generate a CreditProcessor
with the qualifier @Economy
. It does this by instantiating a static inner class called StreetCreditProcessor
, but also notice that this type is not annotated explicitly. The CDI container will locate this particular bean type and create it by instantiating a Household
object for the lifetime of the container, and then invoking the production method, when required by the injection point. The conversation context of the supplied bean is decided at the injection point, as you can see in the following unit test:
package je7hb.standalone; import je7hb.travelfunk.AbstractCdiContainerTest; import org.junit.Test; import javax.inject.Inject; import static org.junit.Assert.*; public class CreditProcessorTest extends AbstractCdiContainerTest { private @Inject @Economy CreditProcessor agent; @Test public void shouldInjectStreetCredit() { assertNotNull(agent); agent.check("12354678"); System.out.printf("agent=%s ", agent ); } }
It is instructive to examine the following output from the program with the CDI container test debugging switched on.
The output from the program is as follows:
AbstractCdiContainerTest#startUpContainer() cdiContainer=null 29 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.9 (Final) 117 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 ... Initialization from CDI Complete. AbstractCdiContainerTest#setUp() containerRefCount=1, cdiContainer=org.apache.deltaspike.cdise.weld.WeldContainerControl@49b35574 agent = StreetCreditProcessor{workerId = 'promoter1000'} AbstractCdiContainerTest#tearDown() containerRefCount = 1, cdiContainer = org.apache.deltaspike.cdise.weld.WeldContainerControl@49b35574 AbstractCdiContainerTest#shutdownContainer() cdiContainer = org.apache.deltaspike.cdise.weld.WeldContainerControl@49b35574 Process finished with exit code 0
18.191.186.219