65.9K
CodeProject is changing. Read more.
Home

CDI Magic for Beginners

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3 votes)

Jul 8, 2017

CPOL

1 min read

viewsIcon

4176

CDI magic for beginners

We have an annotation for this!

When once annotations has been introduced, they used to be just a metadata storage for the real code developers would write. Java EE Contexts and Dependency Injection mechanism it not well-known yet, but allows quite easy and exciting annotation-driven injections of POJOs in managed beans. No more constructor based injections, no ladder-styled signatures and dependency hell, CDI will handle everything in a simple declarative manner.

For example, assume we want to inject two clock components: UTC clock and local timezone clock. In plain Java it will look like:

@Stateful
class Component {
    private Clock utc;
    private Clock local;

    public void setUtc(Clock utc) {
        this.utc = utc;
    }

    public void setLocal(Clock local) {
        this.local = local;
    }
}

component.setUtc(Clock.systemUTC());
component.setLocal(Clock.systemDefaultZone());</code>

Java CDI allows us to extract dependency declaration on per-project basis and inject those clocks based on annotation contexts. First of all, we declare contextual annotations for UTC and local timezones:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
public @interface UTC {
}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
public @interface LocalTime {
}</code>

@Qualifier annotation tells CDI that @UTC and @LocalTime are contextual annotations capable of injected interfaces implementations separation.

Then we declare injections provider capable of supplying Clock implementation based on context qualifier:

@Singleton
public class Producers {

    @Produces
    @UTC
    public static final Clock UTC_CLOCK = Clock.systemUTC();

    @Produces
    @LocalTime
    public static final Clock LOCAL_CLOCK = Clock.systemDefaultZone();
}

From now on, CDI will get Producers.UTC_CLOCK and Producers.LOCAL_CLOCK on every injection marked with @UTC or @LocalTime qualifier respectively, allowing us to focus on application logic, not dependency injection infrastructure. For example, let's rewrite our Component to use CDI mechanisms:

@Stateful
class Component {

    @Inject
    @UTC
    Clock utc;
    
    @Inject
    @LocalTime
    Clock local;
}

Once Component bean instance is created, both utc and local fields will be filled with Producers.UTC_CLOCK and Producers.LOCAL_CLOCK respectively. No other actions required, CDI will make all the magic to make this work.