available in the JSF Expression Language
(EL) with the @Named annotation and
define a scope such as @RequestScoped.
Here is an example of using explicit
annotations for JSF integration:
@Named
@RequestScoped
@Nice(PERSONAL)
public class Greeter {}
The InterceptorBinding annotation can
be combined with stereotypes, which
greatly reduces the amount of annota-
tion declaration. Here is a decorated
presenter stereotype:
@Model
@Nice(PERSONAL)
@Stereotype
@Target(ElementType.TYPE)
@Retention( RetentionPolicy.RUNTIME)
public @interface NicePresenter {}
@Stereotype works like a macro. All
annotations placed on @Stereotype are
going to be expanded. @Stereotype is just
an annotation container without any
additional semantics. The expansion is
recursive; a stereotype can be annotated
with other stereotypes. Listing 8 shows
the built-in @Stereotype javax.enterprise
. inject.Model.
The NicePresenter shown above was
annotated with @Model, which in turn is
a built-in stereotype containing the
@Named and @RequestScoped annotations (see Listing 8). Also, in the case
of stereotypes, you have to activate the
interceptors in the beans.xml file.
Separation of Cross-Cutting Concerns
The majority of the interceptor code
deals with generic invocations and
reflection. The parameter javax
. interceptor.InvocationContext carries
the target method, its parameters, and
additional context data, which are usually used to preprocess and postprocess
the call. This metadata processing is
usually not reusable, and it is hard to
test. Listing 9 shows the delegation of
functionality to a separate class.
Interceptors are executed in the scope
of the target bean. They participate in
the transaction, they are executed in
the security context, and their lifecycle
is identical to the intercepted bean.
Reusable cross-cutting functionality can
be easily factored out into an independent, reusable bean and injected into
the interceptor. Listing 10 shows a reusable audit class.
There are no specific requirements
for the reusable class. It can be any
POJO (as in Listing 10), a Contexts and
Dependency Injection (CDI)–managed
bean, or an EJB 3. 1 bean. The current
execution contexts (transactions, security, and context data) are passed to the
injected class as well.
The interceptor method denoted with
the @AroundInvoke annotation should
implement only the generic code necessary to interpret InvocationContext. Any
reusable aspects or functionality should
be extracted into separate methods or
independent classes. Such a separation
simplifies unit testing of the reusable
code, as well as integration testing for the
interceptor implementation itself.
<beans>
<interceptors>
<class>(...). aop.interceptors.NicenessExtender</class>
</beans>
COMMUNITY
JAVA IN ACTION
Download all listings in this issue as text
ABOUT US
There Are Some Limits
Unlike AOP frameworks with “before”
and “after” advice (that is, interception
points), interceptors are only able to
wrap the whole method with the
@AroundInvoke annotation. Custom
actions can be performed before and
after the invocation, but you have to trigger the invocation of the target manually
with the InvocationContext#proceed()
call yourself.
Also, AOP frameworks come with
powerful tools to find the interception
points (pointcuts, in the AOP terminol-
ogy). Unlike Java EE 6, AOP frameworks
are able to decorate not only methods
but also constructors and even fields.
Java EE 6 interceptors are limited to
method decoration only.