Weld SiteCommunity Documentation

Chapter 9. Interceptors

9.1. Interceptor bindings
9.2. Implementing interceptors
9.3. Enabling interceptors
9.4. Interceptor bindings with members
9.5. Multiple interceptor binding annotations
9.6. Interceptor binding type inheritance
9.7. Use of @Interceptors
9.8. Enhanced version of javax.interceptor.InvocationContext

Interceptor functionality is defined in the Java Interceptors specification.

The Interceptors specification defines three kinds of interception points:

A business method interceptor applies to invocations of methods of the bean by clients of the bean:

public class TransactionInterceptor {

   @AroundInvoke
   public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

A lifecycle callback interceptor applies to invocations of lifecycle callbacks by the container:

public class DependencyInjectionInterceptor {

   @PostConstruct
   public void injectDependencies(InvocationContext ctx) { ... }
}

An interceptor class may intercept both lifecycle callbacks and business methods.

A timeout method interceptor applies to invocations of EJB timeout methods by the container:

public class TimeoutInterceptor {

   @AroundTimeout
   public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

Suppose we want to declare that some of our beans are transactional. The first thing we need is an interceptor binding type to specify exactly which beans we’re interested in:

@InterceptorBinding

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}

Now we can easily specify that our ShoppingCart is a transactional object:

@Transactional

public class ShoppingCart { ... }

Or, if we prefer, we can specify that just one method is transactional:

public class ShoppingCart {

   @Transactional public void checkout() { ... }
}

That’s great, but somewhere along the line we’re going to have to actually implement the interceptor that provides this transaction management aspect. All we need to do is create a standard interceptor, and annotate it @Interceptor and @Transactional.

@Transactional @Interceptor

public class TransactionInterceptor {
   @AroundInvoke
   public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

Interceptors can take advantage of dependency injection:

@Transactional @Interceptor

public class TransactionInterceptor {
    @Resource UserTransaction transaction;
    @AroundInvoke
    public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

Multiple interceptors may use the same interceptor binding type.

By default, all interceptors are disabled. We need to enable our interceptor. We can do it using beans.xml descriptor of a bean archive. However, this activation only applies to the beans in that archive. From CDI 1.1 onwards the interceptor can be enabled for the whole application using @Priority annotation.


<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">
   <interceptors>
      <class>org.mycompany.myapp.TransactionInterceptor</class>
   </interceptors>
</beans>

Whoah! Why the angle bracket stew?

Well, having the XML declaration is actually a good thing. It solves two problems:

Having two interceptors without @Priority, we could specify that our security interceptor runs before our transaction interceptor.


<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">
   <interceptors>
      <class>org.mycompany.myapp.SecurityInterceptor</class>
      <class>org.mycompany.myapp.TransactionInterceptor</class>
   </interceptors>
</beans>

Or we could turn them both off in our test environment by simply not mentioning them in beans.xml! Ah, so simple.

It gets quite tricky when used along with interceptors annotated with @Priority. Interceptors enabled using @Priority are called before interceptors enabled using beans.xml, the lower priority values are called first.

Suppose we want to add some extra information to our @Transactional annotation:

@InterceptorBinding

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
   boolean requiresNew() default false;
}

CDI will use the value of requiresNew to choose between two different interceptors, TransactionInterceptor and RequiresNewTransactionInterceptor.

@Transactional(requiresNew = true) @Interceptor

public class RequiresNewTransactionInterceptor {
   @AroundInvoke
   public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

Now we can use RequiresNewTransactionInterceptor like this:

@Transactional(requiresNew = true)

public class ShoppingCart { ... }

But what if we only have one interceptor and we want the container to ignore the value of requiresNew when binding interceptors? Perhaps this information is only useful for the interceptor implementation. We can use the @Nonbinding annotation:

@InterceptorBinding

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
   @Nonbinding String[] rolesAllowed() default {};
}

Usually we use combinations of interceptor bindings types to bind multiple interceptors to a bean. For example, the following declaration would be used to bind TransactionInterceptor and SecurityInterceptor to the same bean:

@Secure(rolesAllowed="admin") @Transactional

public class ShoppingCart { ... }

However, in very complex cases, an interceptor itself may specify some combination of interceptor binding types:

@Transactional @Secure @Interceptor

public class TransactionalSecureInterceptor { ... }

Then this interceptor could be bound to the checkout() method using any one of the following combinations:

public class ShoppingCart {

   @Transactional @Secure public void checkout() { ... }
}
@Secure

public class ShoppingCart {
   @Transactional public void checkout() { ... }
}
@Transactional

public class ShoppingCart {
   @Secure public void checkout() { ... }
}
@Transactional @Secure

public class ShoppingCart {
   public void checkout() { ... }
}

One limitation of the Java language support for annotations is the lack of annotation inheritance. Really, annotations should have reuse built in, to allow this kind of thing to work:

public @interface Action extends Transactional, Secure { ... }

Well, fortunately, CDI works around this missing feature of Java. We may annotate one interceptor binding type with other interceptor binding types (termed a meta-annotation). The interceptor bindings are transitive — any bean with the first interceptor binding inherits the interceptor bindings declared as meta-annotations.

@Transactional @Secure

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

Now, any bean annotated @Action will be bound to both TransactionInterceptor and SecurityInterceptor. (And even TransactionalSecureInterceptor, if it exists.)

The @Interceptors annotation defined by the Interceptors specification (and used by the Managed Beans and EJB specifications) is still supported in CDI.

@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})

public class ShoppingCart {
   public void checkout() { ... }
}

However, this approach suffers the following drawbacks:

Therefore, we recommend the use of CDI-style interceptor bindings.

For even more control over interceptors, Weld offers enhanced version of javax.interceptor.InvocationContext - org.jboss.weld.interceptor.WeldInvocationContext. It comes with two additional methods - getInterceptorBindings and getInterceptorBindingsByType(Class<T> annotationType). You shouldn’t need this in most cases, but it comes handy when working with @Nonbinding values in interceptor binding annotations.

Assume you have the following interceptor binding:

@InterceptorBinding

@Inherited
@Target({ TYPE, METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
public @interface FooBinding {
    @Nonbinding
    String secret() default "";
}

Then, in the interceptor class, you can retrieve the secret String in the following way:

@Priority(value = Interceptor.Priority.APPLICATION)

@Interceptor
@FooBinding(secret = "nonbinding")
public class AroundConstructInterceptor {
    @SuppressWarnings("unchecked")
    @AroundConstruct
    void intercept(InvocationContext ctx) throws Exception {
        if(ctx instanceof WeldInvocationContext) {
            Set<Annotation> bindings =  ((WeldInvocationContext)ctx).getInterceptorBindings();
        for (Annotation annotation : bindings) {
                if (annotation.annotationType().equals(FooBinding.class)) {
                    FooBinding fooBinding = (FooBinding) annotation;
                    String secret = fooBinding.secret();
                }
            }
        }
        ctx.proceed();
    }
}

WeldInvocationContext can be used with the following interceptor types:

Alternatively, you can gain access to these binding directly from InvocationContext as we store them there using a key org.jboss.weld.interceptor.bindings. This key is easily accessible from WeldInvocationContext.INTERCEPTOR_BINDINGS_KEY. Let’s alter the previous example to demonstrate this:

@Priority(value = Interceptor.Priority.APPLICATION)

@Interceptor
@FooBinding(secret = "nonbinding")
public class AroundConstructInterceptor {
    @SuppressWarnings("unchecked")
    @AroundConstruct
    void intercept(InvocationContext ctx) throws Exception {
        // retrieve data directly from InvocationContext
        Set<Annotation> bindings = (Set<Annotation>) ctx.getContextData().get(WeldInvocationContext.INTERCEPTOR_BINDINGS_KEY);
    if (bindings != null) {
            for (Annotation annotation : bindings) {
                if (annotation.annotationType().equals(FooBinding.class)) {
                    FooBinding fooBinding = (FooBinding) annotation;
                    String secret = fooBinding.secret();
                }
            }
        }
        ctx.proceed();
    }
}
[[decorators]]
== Decorators
Interceptors are a powerful way to capture and separate concerns which
are _orthogonal_ to the application (and type system). Any interceptor
is able to intercept invocations of any Java type. This makes them
perfect for solving technical concerns such as transaction management,
security and call logging. However, by nature, interceptors are unaware
of the actual semantics of the events they intercept. Thus, interceptors
aren't an appropriate tool for separating business-related concerns.
The reverse is true of _decorators_. A decorator intercepts invocations
only for a certain Java interface, and is therefore aware of all the
semantics attached to that interface. Since decorators directly
implement operations with business semantics, it makes them the perfect
tool for modeling some kinds of business concerns. It also means that a
decorator doesn't have the generality of an interceptor. Decorators
aren't able to solve technical concerns that cut across many disparate
types. Interceptors and decorators, though similar in many ways, are
complementary. Let's look at some cases where decorators fit the bill.
Suppose we have an interface that represents accounts:
[source.JAVA, java]
-------------------------------------------
public interface Account {
   public BigDecimal getBalance();
   public User getOwner();
   public void withdraw(BigDecimal amount);
   public void deposit(BigDecimal amount);
}
-------------------------------------------
Several different beans in our system implement the `Accountinterface.
However, we have a common legal requirement that; for any kind of
account, large transactions must be recorded by the system in a special
log. This is a perfect job for a decorator.
A decorator is a bean (possibly even an abstract class) that implements
the type it decorates and is annotated `@Decorator`.
[source.JAVA, java]
-----------------------------------------------
@Decorator
public abstract class LargeTransactionDecorator
      implements Account {
   ...
}
-----------------------------------------------
The decorator implements the methods of the decorated type that it wants
to intercept.
[source.JAVA, java]
-----------------------------------------------
@Decorator
public abstract class LargeTransactionDecorator
      implements Account {
   @Inject @Delegate @Any Account account;
   @PersistenceContext EntityManager em;
   public void withdraw(BigDecimal amount) {
      ...
   }
   public void deposit(BigDecimal amount);
      ...
   }
}
-----------------------------------------------
Unlike other beans, a decorator may be an abstract class. Therefore, if
there's nothing special the decorator needs to do for a particular
method of the decorated interface, you don't need to implement that
method.
Interceptors for a method are called before decorators that apply to the
method.
=== Delegate object
Decorators have a special injection point, called the _delegate
injection point_, with the same type as the beans they decorate, and the
annotation `@Delegate`. There must be exactly one delegate injection
point, which can be a constructor parameter, initializer method
parameter or injected field.
[source.JAVA, java]
-----------------------------------------------
@Decorator
public abstract class LargeTransactionDecorator
      implements Account {
   @Inject @Delegate @Any Account account;
   ...
}
-----------------------------------------------
A decorator is bound to any bean which:
* has the type of the delegate injection point as a bean type, and
* has all qualifiers that are declared at the delegate injection point.
This delegate injection point specifies that the decorator is bound to
all beans that implement `Account`:
[source.JAVA, java]
---------------------------------------
@Inject @Delegate @Any Account account;
---------------------------------------
A delegate injection point may specify any number of qualifier
annotations. The decorator will only be bound to beans with the same
qualifiers.
[source.JAVA, java]
-------------------------------------------
@Inject @Delegate @Foreign Account account;
-------------------------------------------
The decorator may invoke the delegate object, which has much the same
effect as calling `InvocationContext.proceed()` from an interceptor. The
main difference is that the decorator can invoke _any_ business method
on the delegate object.
[source.JAVA, java]
---------------------------------------------------
@Decorator
public abstract class LargeTransactionDecorator
      implements Account {
   @Inject @Delegate @Any Account account;
   @PersistenceContext EntityManager em;
   public void withdraw(BigDecimal amount) {
      account.withdraw(amount);
      if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
         em.persist( new LoggedWithdrawl(amount) );
      }
   }
   public void deposit(BigDecimal amount);
      account.deposit(amount);
      if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
         em.persist( new LoggedDeposit(amount) );
      }
   }
}
---------------------------------------------------
=== Enabling decorators
By default, all decorators are disabled. We need to _enable_ our
decorator. We can do it using `beans.xml` descriptor of a bean archive.
However, this activation only applies to the beans in that archive. From
CDI 1.1 onwards the decorator can be enabled for the whole application
using `@Priority` annotation.
[source.XML, xml]
---------------------------------------------------------------------
<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">
   <decorators>
         <class>org.mycompany.myapp.LargeTransactionDecorator</class>
   </decorators>
</beans>
---------------------------------------------------------------------
This declaration serves the same purpose for decorators that the
`<interceptors>` declaration serves for interceptors:
* it enables us to specify an ordering for decorators in our system,
ensuring deterministic behavior, and
* it lets us enable or disable decorator classes at deployment time.
Decorators enabled using `@Priority` are called before decorators
enabled using `beans.xml`, the lower priority values are called first.
NOTE: Having a decorator enabled by `@Priority` and in the same time listed
in `beans.xml` leads to a non-portable behaviour! This combination of enablement
should therefore be avoided in order to maintain consistent behaviour across
different CDI implementations.
As for Weld, such decorator is only invoked once in the `@Priority part of the
invocation chain. E.g. the enablement via `beans.xml` will be ignored.
[[events]]
== Events
Dependency injection enables loose-coupling by allowing the
implementation of the injected bean type to vary, either at deployment
time or runtime. Events go one step further, allowing beans to interact
with no compile time dependency at all. Event _producers_ raise events
that are delivered to event _observers_ by the container.
This basic schema might sound like the familiar observer/observable
pattern, but there are a couple of twists:
* not only are event producers decoupled from observers; observers are
completely decoupled from producers,
* observers can specify a combination of "selectors" to narrow the set
of event notifications they will receive, and
* observers can be notified immediately, or can specify that delivery of
the event should be delayed until the end of the current transaction.
The CDI event notification facility uses more or less the same typesafe
approach that we've already seen with the dependency injection service.
=== Event payload
The event object carries state from producer to consumer. The event
object is nothing more than an instance of a concrete Java class. (The
only restriction is that an event type may not contain type variables).
An event may be assigned qualifiers, which allows observers to
distinguish it from other events of the same type. The qualifiers
function like topic selectors, allowing an observer to narrow the set of
events it observes.
An event qualifier is just a normal qualifier, defined using
`@Qualifier`. Here's an example:
[source.JAVA, java]
-----------------------------------------
@Qualifier
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RUNTIME)
public @interface Updated {}
-----------------------------------------
=== Event observers
An _observer method_ is a method of a bean with a parameter annotated
`@Observes`.
[source.JAVA, java]
-------------------------------------------------------------------
public void onAnyDocumentEvent(@Observes Document document) { ... }
-------------------------------------------------------------------
The annotated parameter is called the _event parameter_. The type of the
event parameter is the observed _event type_, in this case `Document`.
The event parameter may also specify qualifiers.
[source.JAVA, java]
-----------------------------------------------------------------------------
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
-----------------------------------------------------------------------------
An observer method need not specify any event qualifiersin this case it
is interested in every event whose type is assignable to the observed event type.
Such observer will trigger on both events shown below:
[source.JAVA, java]
-------------------------------------------
@Inject @Any Event<Document> documentEvent;
@Inject @Updated Event<Document> anotherDocumentEvent;
-------------------------------------------
If the observer does specify qualifiers, it will be notified of an event if the event
object is assignable to the observed event type, and if the set of observed event
qualifiers is a subset of all the event qualifiers of the event.
The observer method may have additional parameters, which are injection
points:
[source.JAVA, java]
----------------------------------------------------------------------------------------
public void afterDocumentUpdate(@Observes @Updated Document document, User user) { ... }
----------------------------------------------------------------------------------------
=== Event producers
Event producers fire events using an instance of the parameterized
`Eventinterface. An instance of this interface is obtained by
injection:
[source.JAVA, java]
-------------------------------------------
@Inject @Any Event<Document> documentEvent;
-------------------------------------------
A producer raises events by calling the `fire()` method of the `Event`
interface, passing the event object:
[source.JAVA, java]
-----------------------------
documentEvent.fire(document);
-----------------------------
This particular event will be delivered to every observer method that:
* has an event parameter to which the event object (the `Document`) is
assignable, and
* specifies no qualifiers.
The container simply calls all the observer methods, passing the event
object as the value of the event parameter. If any observer method
throws an exception, the container stops calling observer methods, and
the exception is rethrown by the `fire()` method.
Qualifiers can be applied to an event in one of two ways:
* by annotating the `Event` injection point, or
* by passing qualifiers to the `select()` of `Event`.
Specifying the qualifiers at the injection point is far simpler:
[source.JAVA, java]
------------------------------------------------------
@Inject @Updated Event<Document> documentUpdatedEvent;
------------------------------------------------------
Then, every event fired via this instance of `Event` has the event
qualifier `@Updated`. The event is delivered to every observer method
that:
* has an event parameter to which the event object is assignable, and
* does not have any event qualifier _except_ for the event qualifiers
that match those specified at the `Event` injection point.
The downside of annotating the injection point is that we can't specify
the qualifier dynamically. CDI lets us obtain a qualifier instance by
subclassing the helper class `AnnotationLiteral`. That way, we can pass
the qualifier to the `select()` method of `Event`.
[source.JAVA, java]
------------------------------------------------------------------------
documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);
------------------------------------------------------------------------
Events can have multiple event qualifiers, assembled using any
combination of annotations at the `Event` injection point and qualifier
instances passed to the `select()` method.
=== Conditional observer methods
By default, if there is no instance of an observer in the current
context, the container will instantiate the observer in order to deliver
an event to it. This behavior isn't always desirable. We may want to
deliver events only to instances of the observer that already exist in
the current contexts.
A conditional observer is specified by adding `receive = IF_EXISTS` to
the `@Observes` annotation.
[source.JAVA, java]
-----------------------------------------------------------------------------------------------
public void refreshOnDocumentUpdate(@Observes(receive = IF_EXISTS) @Updated Document d) { ... }
-----------------------------------------------------------------------------------------------
NOTE: A bean with scope `@Dependent` cannot be a conditional observer, since
it would never be called!
=== Event qualifiers with members
An event qualifier type may have annotation members:
[source.JAVA, java]
-----------------------------------------
@Qualifier
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RUNTIME)
public @interface Role {
   RoleType value();
}
-----------------------------------------
The member value is used to narrow the messages delivered to the
observer:
[source.JAVA, java]
------------------------------------------------------------------------
public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... }
------------------------------------------------------------------------
Event qualifier type members may be specified statically by the event
producer, via annotations at the event notifier injection point:
[source.JAVA, java]
---------------------------------------------------
@Inject @Role(ADMIN) Event<LoggedIn> loggedInEvent;
---------------------------------------------------
Alternatively, the value of the event qualifier type member may be
determined dynamically by the event producer. We start by writing an
abstract subclass of `AnnotationLiteral`:
[source.JAVA, java]
-----------------------------------
abstract class RoleBinding
   extends AnnotationLiteral<Role>
   implements Role {}
-----------------------------------
The event producer passes an instance of this class to `select()`:
[source.JAVA, java]
-------------------------------------------------
documentEvent.select(new RoleBinding() {
   public void value() { return user.getRole(); }
}).fire(document);
-------------------------------------------------
=== Multiple event qualifiers
Event qualifiers may be combined, for example:
[source.JAVA, java]
-------------------------------------------------------------------------------------------
@Inject @Blog Event<Document> blogEvent;
...
if (document.isBlog()) blogEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);
-------------------------------------------------------------------------------------------
The above shown event is fired with two qualifiers - `@Blog` and `@Updated`.
An observer method is notified if the set of observer qualifiers is a subset of the fired event's qualifiers.
Assume the following observers in this example:
[source.JAVA, java]
-------------------------------------------------------------------------------
public void afterBlogUpdate(@Observes @Updated @Blog Document document) { ... }
-------------------------------------------------------------------------------
[source.JAVA, java]
-----------------------------------------------------------------------------
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
-----------------------------------------------------------------------------
[source.JAVA, java]
---------------------------------------------------------------------
public void onAnyBlogEvent(@Observes @Blog Document document) { ... }
---------------------------------------------------------------------
[source.JAVA, java]
---------------------------------------------------------------------
public void onAnyDocumentEvent(@Observes Document document) { ... }}}
---------------------------------------------------------------------
All of these observer methods will be notified.
However, if there were also an observer method:
[source.JAVA, java]