Stereotypes

The CDI specification defines a stereotype as follows:

In many systems, use of architectural patterns produces a set of recurring bean roles. A stereotype allows a framework developer to identify such a role and declare some common metadata for beans with that role in a central place.

A stereotype encapsulates any combination of:

  • a default scope, and

  • a set of interceptor bindings.

A stereotype may also specify that:

  • all beans with the stereotype have defaulted bean names, or that

  • all beans with the stereotype are alternatives.

A bean may declare zero, one or multiple stereotypes. Stereotype annotations may be applied to a bean class or producer method or field.

A stereotype is an annotation, annotated @Stereotype, that packages several other annotations. For instance, the following stereotype identifies action classes in some MVC framework:

@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
...
public @interface Action {}

We use the stereotype by applying the annotation to a bean.

@Action
public class LoginAction { ... }

Of course, we need to apply some other annotations to our stereotype or else it wouldn’t be adding much value.

Default scope for a stereotype

A stereotype may specify a default scope for beans annotated with the stereotype. For example:

@RequestScoped
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}

A particular action may still override this default if necessary:

@Dependent @Action
public class DependentScopedLoginAction { ... }

Naturally, overriding a single default isn’t much use. But remember, stereotypes can define more than just the default scope.

Interceptor bindings for stereotypes

A stereotype may specify a set of interceptor bindings to be inherited by all beans with that stereotype.

@RequestScoped
@Transactional(requiresNew=true)
@Secure
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}

This helps us get technical concerns, like transactions and security, even further away from the business code!

Name defaulting with stereotypes

We can specify that all beans with a certain stereotype have a defaulted EL name when a name is not explicitly defined for that bean. All we need to do is add an empty @Named annotation:

@RequestScoped
@Transactional(requiresNew=true)
@Secure
@Named
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}

Now, the LoginAction bean will have the defaulted name loginAction.

Alternative stereotypes

A stereotype can indicate that all beans to which it is applied are `@Alternative`s. An alternative stereotype lets us classify beans by deployment scenario.

@Alternative
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Mock {}

We can apply an alternative stereotype to a whole set of beans, and activate them all with one line of code in beans.xml.

@Mock
public class MockLoginAction extends LoginAction { ... }
<beans>
   <alternatives>
      <stereotype>org.mycompany.testing.Mock</stereotype>
   </alternatives>
</beans>

Stereotypes with @Priority

A stereotype can declare a @Priority annotation which then affects enablement and ordering of beans. This is typically useful in combination with @Alternative to immediately mark a bean as a globally enabled alternative:

@Alternative
@Priority(Interceptor.Priority.APPLICATION + 5)
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface EnabledAlternativeStereotype {}

A @Priority annotation declared directly on the bean always precedes any @Priority annotation inherited via stereotypes.

Stereotype stacking

This may blow your mind a bit, but stereotypes may declare other stereotypes, which we’ll call stereotype stacking. You may want to do this if you have two distinct stereotypes which are meaningful on their own, but in other situation may be meaningful when combined.

Here’s an example that combines the @Action and @Auditable stereotypes:

@Auditable
@Action
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface AuditableAction {}

Built-in stereotypes

CDI defines one standard stereotype, @Model, which is expected to be used frequently in web applications:

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

Instead of using JSF managed beans, just annotate a bean @Model, and use it directly in your JSF view!