Search code examples
javajakarta-eedesign-patternsdecoratorinterceptor

Difference between interceptors and decorators


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?


Solution

  • Decorator

    One difference would be, as your example shows it, with decorator one usually writes 1 decorator per 1 decorated class/interface.

    Decorator example

    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
        }
    }
    

    Interceptor

    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.

    Interceptor example

    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.