Understanding Jakarta EE 8 - C.D.I. (Part 3) - Defining custom CDI annotations.

The CDI specification allows developers the flexibility to create new types that are within the scopes of the bean type declaration.
In this example we will examine and learn how easy it is to create custom CDI annotations for defining:

  • New qualifier types.
  • New Stereotypes.

Defining new qualifier types.

A qualifier type is a Java annotation defined as @Retention(RUNTIME). Typically a qualifier type is defined as @Target({METHOD, FIELD, PARAMETER, TYPE}).

Defining a qualifier type may be declared by specifying the @javax.inject.Qualifier meta-annotation.

In our example, we've created 2 service-defined qualifier types, @Jabbawockee and @LesTwins qualifiers.

@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface Jabbawockee {

}
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface LesTwins {

}

And a bean is qualified by annotating the bean class or producer method or field with the qualifier type.

@Jabbawockee
public class JabbawockeeService implements Service {

    public void doWork() {
        System.out.println("Jabbawockee doing the work.");
    }
}

Stereotypes

The JavaEE specification specifies stereotypes as:

A stereotype is a kind of annotation, applied to a bean, that incorporates other annotations. Stereotypes can be particularly useful in large applications in which
you have a number of beans that perform similar functions.

A well-known stereotypes, known by Enterprise Java Developers, are from Spring Framework: @Component, @Service and @Repository stereotypes.

A stereotype is an annotation, annotated @Stereotype(@javax.enterprise.inject.Stereotype), that packages several other annotations. For instance, to recreate the 3 stereotypes from Spring Framework into your JavaEE application:

@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
@Documented
@Named
public @interface Component {}

Note that our Component stereotype has been declared with an empty @Named annotation, which specifies that every bean with the stereotype has a defaulted name when a name is not explicitly specified by the bean. A @Named qualifier declared by a stereotype is not added to the qualifiers of a bean with the stereotype.

If a stereotype declares a non-empty @Named annotation, the container automatically detects the problem and treats it as a definition error.

@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
@Component //Note that Spring specifies that this annotation is a specialization of Component annotation.
public @interface Service {}
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Repository {}

Stereotype can be specified with interceptor bindings by annotating the stereotype with interceptor binding types. For example, to have a transactional business service, we can annotate our Service stereotype with @Transactional.

@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
@Transactional
@Component
public @interface Service {}

Also, the default scope of a stereotype is defined by annotating the stereotype with a scope type. A stereotype may declare at most one scope. If a stereotype declares more than one scope, the container automatically detects the problem and treats it as a definition error.

For example, in our Controller stereotype, we may specify to have a default @RequestScoped scope type:

@RequestScoped
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
@Documented
@Named
public @interface Component {}

Built-in stereotype.

The CDI framework provides us with a built-in stereotype @javax.enterprise.inject.Model which is intended for use with beans that define the model layer of an MVC web application architecture such as Jakarta Server Faces.

@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface Model {}

In the next article, we will examine Producers (producer method and producer field), injecting using @Produces and Decorators, using the @Decorator annotation.

19