Injection with CDI
Antonio Goncalves
www.antoniogoncalves.org
@agoncal
Module Outline
Basic dependency injection
Qualifiers
Advanced qualifiers
Veto
Alternatives
Basic Dependency Injection
Objects
Objects depend on each other
CDI brings dependency injection
Type safe way
Loose coupling
Strong typing
Depending on a Class
The IsbnGenerator Class
public class IsbnGenerator {
public String generateNumber() {
return "13-84356-" + Math.abs(new Random().nextInt());
}
}
The BookService Class
public class BookService {
@Inject
private IsbnGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injection Point on Field
public class BookService {
@Inject Injection Point
private IsbnGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injection Point on Constructor
public class BookService {
Injection Point
private IsbnGenerator generator;
@Inject
public BookService(IsbnGenerator generator) {
this.generator = generator;
}
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injection Point on Setter
public class BookService {
Injection Point
private IsbnGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
@Inject
public void setGenerator(IsbnGenerator generator) {
this.generator = generator;
}
}
Deployment Descriptor
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
beans.xml
Deployment Descriptor
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="none">
</beans>
beans.xml
Deployment Descriptor
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="annotated">
</beans>
beans.xml
Depending on One Implementation
Depending on One Implementation
Interface and One Implementation
public interface NumberGenerator {
String generateNumber();
}
public class IsbnGenerator implements NumberGenerator {
public String generateNumber() {
return "13-84356-" + Math.abs(new Random().nextInt());
}
}
Injecting One Implementation
public class BookService {
@Inject
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Ambiguous Injection
Default Qualifier
Having Different Qualifiers
Having Different Qualifiers
Having Different Qualifiers
@ThirteenDigits and @EightDigits Qualifiers
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface ThirteenDigits {
}
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface EightDigits {
}
Two Qualified Implementations
public interface NumberGenerator {
String generateNumber();
}
@ThirteenDigits
public class IsbnGenerator implements NumberGenerator {
public String generateNumber() {
return "13-84356-" + Math.abs(new Random().nextInt());
}
}
@EightDigits
public class IssnGenerator implements NumberGenerator {
public String generateNumber() {
return "8-" + Math.abs(new Random().nextInt());
}
}
Injecting the IsbnGenerator
public class BookService {
@Inject
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injecting the IsbnGenerator
public class BookService {
@Inject @ThirteenDigits
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injecting the IssnGenerator
public class BookService {
@Inject @EightDigits
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Dealing with Many Implementations
…
Qualifier with Members
@Target({FIELD, TYPE, METHOD})
@Retention(RUNTIME)
@Qualifier
public @interface Generator {
NumberOfDigits numberOfDigits();
boolean printed();
public enum NumberOfDigits{
EIGHT,
THIRTEEN
}
}
Qualifiers with Members on Beans
@Generator(numberOfDigits = THIRTEEN, printed = false)
public class EIsbnGenerator implements NumberGenerator {
...
}
@Generator(numberOfDigits = EIGHT, printed = false)
public class EIssnGenerator implements NumberGenerator {
...
}
@Generator(numberOfDigits = THIRTEEN, printed = true)
public class PIsbnGenerator implements NumberGenerator {
...
}
@Generator(numberOfDigits = EIGHT, printed = true)
public class PIssnGenerator implements NumberGenerator {
...
}
Injecting a Bean with Qualifier with Members
public class BookService {
@Inject @Generator(numberOfDigits = THIRTEEN,
printed = false)
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injecting a Bean with Qualifier with Members
public class BookService {
@Inject @Generator(numberOfDigits = THIRTEEN,
printed = true)
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Injecting a Bean with Qualifier with Members
public class BookService {
@Inject @Generator(numberOfDigits = EIGHT,
printed = true)
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Aggregating Multiple Qualifiers
Aggregating Multiple Qualifiers
Aggregating Multiple Qualifiers
Multiple Qualifiers
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface ThirteenDigits { }
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface EightDigits { }
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface Electronic { }
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface Print { }
Multiple Qualifiers on Beans
@ThirteenDigits @Electronic
public class EIsbnGenerator implements NumberGenerator {
...
}
@EightDigits @Electronic
public class EIssnGenerator implements NumberGenerator {
...
}
@ThirteenDigits @Print
public class PIsbnGenerator implements NumberGenerator {
...
}
@EightDigits @Print
public class PIssnGenerator implements NumberGenerator {
...
}
Injecting a Bean with Multiple Qualifiers
public class BookService {
@Inject @ThirteenDigits @Electronic
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Veto
Depending on the beans.xml
bean-discovery-mode="annotated"
bean-discovery-mode="all"
bean-discovery-mode="none"
Veto a bean
Veto a package
@Vetoed
Prevent the processing
Ambiguous Injection
Deployment Descriptor
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
beans.xml
Veto
One Bean Is Vetoed
public class BookService {
@Inject @Default
private NumberGenerator generator;
public Book createBook(String title) {...}
}
@Vetoed
public class IsbnGenerator implements NumberGenerator {
public String generateNumber() {...}
}
public class IssnGenerator implements NumberGenerator {
public String generateNumber() {...}
}
One Package Is Vetoed
package-info.java
@Vetoed
package com.pluralsight.injection;
import javax.enterprise.inject.Vetoed;
Alternatives
Qualifiers at development time
Alternatives at deployment time
Depending on the environment
@Alternative
beans.xml
Default Alternative
@Alternative Implementation
public interface NumberGenerator {
String generateNumber();
}
@Default
public class IsbnGenerator implements NumberGenerator {
public String generateNumber() {
return "13-84356-" + Math.abs(new Random().nextInt());
}
}
@Default
public class MockGenerator implements NumberGenerator {
public String generateNumber() {
return "mock";
}
}
@Alternative Implementation
public interface NumberGenerator {
String generateNumber();
}
public class IsbnGenerator implements NumberGenerator {
public String generateNumber() {
return "13-84356-" + Math.abs(new Random().nextInt());
}
}
@Alternative
public class MockGenerator implements NumberGenerator {
public String generateNumber() {
return "mock";
}
}
Injecting the Alternative
public class BookService {
@Inject
private NumberGenerator generator;
public Book createBook(String title) {
return new Book(title, generator.generateNumber());
}
}
Enabling the Alternative
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
<alternatives>
<class>com.pluralsight.injection.MockGenerator</class>
</alternatives>
</beans>
Alternative for a Given Qualifier
Summary
Dependency injection
Default injection
Qualifiers
Type safe
Annotations with members
Aggregate several qualifiers
Vetos
Alternatives