1 {Java} Annotations Thu Feb 10, 2011 5:35 am
des
Achiever
Want to inject reusable functionality but don’t want your consumers to go through complex set of steps to implement? Using annotations, a reusable capability can be injected at runtime – your clients can take advantage of common, reusable capabilities while avoiding the need to implement boiler plate code. Consumers can also be allowed to declaratively specify/alter the reusable asset’s behavior using this approach. Here is an example using Java and Spring framework to print a test message before invoking the target method.
Create a dynamic proxy – all this does is examines the boolean log method from the annotation and prints a test message:
Create a spring bean post-processor – checks for annotation and creates a proxied version of bean:
Annotate an example interface as Loggable – this model can be used to inject lot of other reusable capabilities (error handling, notifications to JMS destinations, or even perform data transformations):
Finally, each consuming interface will have an implementation and has to be defined as a bean along with the post-processor during spring initialization. This is a trivial example but was meant to illustrate the injection of reusable behavior via java annotations.
- Code:
1 package example.annotation;
2
3 import java.lang.annotation.*;
4
5 @Target(ElementType.TYPE)
6 @Retention(RetentionPolicy.RUNTIME)
7 public @interface Loggable {
8 boolean log() default true;
9 }
Create a dynamic proxy – all this does is examines the boolean log method from the annotation and prints a test message:
- Code:
01 package example.proxy;
02
03 import java.lang.reflect.*;
04 import example.annotation.Loggable;
05
06 public class ExampleDynamicProxy implements InvocationHandler {
07
08 private Loggable loggable = null;
09 private final Object targetObject;
10
11 public ExampleDynamicProxy(Object target, Loggable loggable) {
12 targetObject = target;
13 this.loggable = loggable;
14 }
15
16 public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {
17
18 Object result = null;
19 try {
20 if (loggable.log()) {
21 System.out.println("message before invoking method...");
22 }
23 result = method.invoke(targetObject, arguments);
24 } catch (InvocationTargetException ite) {
25 throw ite.getTargetException();
26 }
27 return result;
28 }
29 }
Create a spring bean post-processor – checks for annotation and creates a proxied version of bean:
- Code:
01 package example.postprocessor;
02
03 import java.lang.reflect.Proxy;
04
05 import org.springframework.beans.BeansException;
06 import org.springframework.beans.factory.config.BeanPostProcessor;
07
08 import example.annotation.Loggable;
09 import example.proxy.ExampleDynamicProxy;
10
11 public class ExampleBeanPostProcessor implements BeanPostProcessor {
12
13 @Override
14 public Object postProcessBeforeInitialization(Object arg0, String arg1)
15 throws BeansException {
16 return arg0;
17 }
18
19 @Override
20 public Object postProcessAfterInitialization(Object arg0, String arg1)
21 throws BeansException {
22
23 Class clz = arg0.getClass();
24 Class[] interfaces = clz.getInterfaces();
25
26 if (interfaces != null && interfaces.length == 1
27 && _interfaces[0].isAnnotationPresent(Loggable.class)) {
28
29 Class _interface = interfaces[0];
30 ClassLoader cl = arg0.getClass().getClassLoader();
31 Loggable loggable = (Loggable)_interface.getAnnotation(Loggable.class);
32 Object proxy= Proxy.newProxyInstance(cl, new Class[] {_interface}, new ExampleDynamicProxy(arg0,loggable));
33
34 return proxy;
35 }
36 return arg0;
37 }
38 }
Annotate an example interface as Loggable – this model can be used to inject lot of other reusable capabilities (error handling, notifications to JMS destinations, or even perform data transformations):
- Code:
1 package example.bean;
2
3 import example.annotation.Loggable;
4
5 @Loggable
6 public interface Example {
7 public String getGreeting();
8 }
Finally, each consuming interface will have an implementation and has to be defined as a bean along with the post-processor during spring initialization. This is a trivial example but was meant to illustrate the injection of reusable behavior via java annotations.