Java CDI. Interceptor is only invoked in the first method call in a class [duplicate]
Asked Answered
D

2

8

I'm using CDI Interceptors and I've realized that only the first method call in a class annotated with @Interceptor is intercepted. In the example below methodB is never intercepted.

@InterceptorBinding
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {

}


@Transactional
@Interceptor
public class TransactionsInterceptor {

    @AroundInvoke
    public Object transactionInterceptor(InvocationContext context) throws Exception {

          System.out.println("Method="+context.getMethod().getName());
          return context.proceed();

    }
}


public Interface AnImportantInterface {
      public void methodA();
      public void methodB();
}

@Transactional
@ThreadScoped
public class AnImportantClass implements AnImportantInterface {

    public void methodA() {

        methodB();
    }

    public void methodB() {

        //This method is never intercepted
    }

}


public class AnotherImportantClass {
    @Inject AnImportantInterface aui;

    public void someMethod() {
        aui.methodA();
    }
}

How can I achieve that methodB be intercepted if methodA is called first? is there some workaround?

Daredevil answered 20/8, 2015 at 23:9 Comment(0)
S
9

It's because you are calling methodB() directly and not via the CDI proxy so the interceptor is never invoked. Interceptors will only be invoked when the CDI bean method is called using its proxy. You should move method B into another CDI bean and @Inject it into this one and from methodA change methodB() to bean2.methodB(..).

Shoal answered 21/8, 2015 at 14:0 Comment(2)
Mostly correct, although its worth pointing out that self injection is not mandated as functioning in the CDI spec.Catarina
@JohnAment As you point out self injection is not mandated in the current CDI spec, though that's not what I was getting at in answer, if it were supported (like it is in the EJB spec) it would make for a cleaner solution. For those interested the RFE for it is here: issues.jboss.org/browse/CDI-414Shoal
P
4

Use self injection. Bean self injection can be achieved in CDI quite easily - just inject an Instance, where T is the implementation.

@Named
public class Foo implements Fooable{

@Inject

private Instance<Foo> foo;

public void executeFirst(){

foo.get().executeSecond();

}

@Transactional

public void executeSecond(){

//do something

}

}

This way, you can execute your method right in the same bean. Make sure to select right scope if the bean is stateful. Also make sure Instance's generic type T is directly the implementation - this ensures implementation of the correct object every time.

Prepotent answered 27/5, 2016 at 16:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.