Are there any differences between interceptors and decorators in Java? Strictly speaking, can I implementing things with decorators which are not possible with interceptors and vice versa?
Except the problem that I would have to examine the method name to add method-specific behavior in an interceptor:
Interceptor:
@Nice
@Interceptor
public class NiceGreeterInterceptor {
@AroundInvoke
public Object decorate(InvocationContext ic) throws Exception {
Method method = ic.getMethod();
String methodName = method.getName();
Object result = ic.proceed();
if (methodName.equals("greet")) {
return "NEW " + result;
}
}
}
Decorator:
@Decorator
public class GreeterDecorator implements Greeter {
@Inject
@Any
@Delegate
private Greeter greeter;
@Override
public String greet() {
return "NEW " + greeter.greet();
}
}
Or is it legitimate to say that I can reproduce all the behavior of decorators with interceptors but it is more comfortable to use decorators?
One difference would be, as your example shows it, with decorator one usually writes 1 decorator per 1 decorated class/interface.
interface Worker {
void work();
}
class Decorated implements Worker {
public void work() {
}
}
class DecoratorByInheritance extends Decorated {
public void work() {
// pre
super.work();
// post
}
}
class DecoratorByComposition implements Worker {
Worker decorated;
DecoratorByComposition(Worker decorated) {
this.decorated = decorated;
}
public void work() {
// pre
this.decorated.work();
// post
}
}
With interceptors, which are part of the AOP concept, one writes 1 interceptor for a bunch of classes / methods, e.g. intercepting all DAO methods and make sure a transaction is open before the invocation and closed after it.
Declare a pointcut (what to match), here we match any method from the MyDao class that starts with insert, has any arguments and any return type.
@Pointcut("execution(* com.example.dao.MyDao.insert*(..))")
public void insertPointcut() {
}
Then we declare an around advice which references the pointcut
@Around(value = "com.example.SystemArchitecture.insertPointcut()")
public void interceptMethod(ProceedingJoinPoint pjp) {
// do pre-work
Object retVal = pjp.proceed();
// do post work
return retVal;
}
}
Interceptors are more flexible but imagine one changes the method name, if decorator is used, we'll get a compiler error, with interceptors, it will not match and won't execute our 'around' logic.