Java: Simple technique for annotation-based code injection?
Using reflection is easy just annotate a method with @Audit, just like test runners in JUnit:
public interface Login {
void login(String name, String password);
}
public class LoginImpl implements Login {
@Audit(handler = LoginHandler.class)
public void login(String name, String password) {
System.out.println("login");
}
}
@Audit is defined as:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit {
Class<? extends Handler> handler();
}
where Handler is:
interface Handler {
void handle();
}
class LoginHandler implements Handler {
public void handle() {
System.out.println("HANDLER CALLED!");
}
}
and now the real code:
public class LoginFactory {
private static class AuditInvocationHandler implements InvocationHandler {
private final Login realLogin;
public AuditInvocationHandler(Login realLogin) {
this.realLogin = realLogin;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method realMethod = realLogin.getClass().getMethod(
method.getName(),
method.getParameterTypes());
Audit audit = realMethod.getAnnotation(Audit.class);
if (audit != null) {
audit.handler().newInstance().handle();
}
return method.invoke(realLogin, args);
}
}
public static Login createLogin() {
return (Login) Proxy.newProxyInstance(
LoginFactory.class.getClassLoader(),
new Class[]{Login.class},
new AuditInvocationHandler(new LoginImpl()));
}
}
@Test:
Login login = LoginFactory.createLogin();
login.login("user", "secret");
login.logout();
output:
HANDLER CALLED! login logout
It's done - use Spring or Guice.
Rolling your own makes sense if you want to know how wheels work, or if you think that you can do something that's significantly lighter. Just be sure that both are true before you undertake it.