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.
Declare an annotation – a simple annotation with a boolean flag:
package example.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
boolean log() default true;
}
Create a dynamic proxy – all this does is examines the boolean log method from the annotation and prints a test message:
package example.proxy;
import java.lang.reflect.*;
import example.annotation.Loggable;
public class ExampleDynamicProxy implements InvocationHandler {
private Loggable loggable = null;
private final Object targetObject;
public ExampleDynamicProxy(Object target, Loggable loggable) {
targetObject = target;
this.loggable = loggable;
}
public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {
Object result = null;
try {
if (loggable.log()) {
System.out.println("message before invoking method...");
}
result = method.invoke(targetObject, arguments);
} catch (InvocationTargetException ite) {
throw ite.getTargetException();
}
return result;
}
}
Create a spring bean post-processor – checks for annotation and creates a proxied version of bean:
package example.postprocessor;
import java.lang.reflect.Proxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import example.annotation.Loggable;
import example.proxy.ExampleDynamicProxy;
public class ExampleBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
return arg0;
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
Class clz = arg0.getClass();
Class[] interfaces = clz.getInterfaces();
if (interfaces != null && interfaces.length == 1
&& _interfaces[0].isAnnotationPresent(Loggable.class)) {
Class _interface = interfaces[0];
ClassLoader cl = arg0.getClass().getClassLoader();
Loggable loggable = (Loggable)_interface.getAnnotation(Loggable.class);
Object proxy= Proxy.newProxyInstance(cl, new Class[] {_interface}, new ExampleDynamicProxy(arg0,loggable));
return proxy;
}
return arg0;
}
}
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):
package example.bean;
import example.annotation.Loggable;
@Loggable
public interface Example {
public String getGreeting();
}
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.
Posted by vijaynarayanan 



