Is interceptor really disabled by default?
Asked Answered
C

2

6

I ran into this confusion today. Quote from Weld's documentation (right under Section 9.3),

By default, all interceptors are disabled. We need to enable our interceptor. We can do it using beans.xml descriptor of a bean archive. However, this activation only applies to the beans in that archive.

However, in the project that I am currently working on, I have an interceptor for profiling a method. My META-INF/beans.xml is basically empty:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">
</beans>

Yet I still get expected logs from that profiling interceptor. So, as the title goes, is interceptor really disabled by default?

BTW, I use weld-se for CDI functionality in the project, since CDI is the only thing I need for the project from the Java EE stack.

update

After messing around interceptors today, I find that if the old @Interceptors is used to indicate the interception implementation class, you don't need to specify anything in the beans.xml. However, if you use interceptor binding, i.e., use the @Interceptor annotation to indicate an interceptor class, you must enable interception by adding the interceptor class to the beans.xml. According to my experience, this is still true for CDI 1.1, as indicated by the version in the beans.xml above. BTW, I use org.jboss.weld.se:weld-se:2.0.4.Final for CDI implementation in this case, which I believe implements CDI 1.1.

Clostridium answered 15/10, 2013 at 6:2 Comment(5)
If you could please link to the documentation. Is it possible that you found a Weld 1.0 or 1.1 doc, but are using Weld 2.0?Honorable
@JohnAment: Good point. I didn't notice which version of Weld my original quote belongs to. In any case, I updated the quote from weld 2.1.0.Final documentation, along with its link.Clostridium
Ok, then yes. I see now. Yes, when you use @Interceptors the interceptors are on by default, since you've created a tight coupling between the intercepted object and the interceptor, it will end up enabling it. However, as noted in the docs @Interceptors is provided by the Interceptor spec, not the EJB or CDI specs, as a result only the rules of the Interceptor spec are expected to be applied (you may find others are as well, but it's not portable).Honorable
@Clostridium As per CDI 1.0 implemented by Weld 1.x for JEE6 specs. I confirm your finding. beans.xml does need to have an Interceptors tag with the interceptor class name as the value if @Interceptors(InterceptorClass.class) is used. In case you prefer the annotation approach (@MyLoggingInterceptor for example), then declaring the com.myorg.LoggingIntercepttingClass in beans.xml is a must.Millda
Annotating the interceptor with @Priority will enable it, without the inclusion of beans.xml. e.g. @Priority(Interceptor.Priority.APPLICATION)Kronos
M
9

To confirm JBT findings in his EDIT. As per CDI specifications 1.0 of JSR-299 implemented by Weld 1.0 for JEE6 specs. Please reference this pointer, which I quote:

By default, a bean archive has no enabled interceptors bound via interceptor bindings. An interceptor must be explicitly enabled by listing the fully qualified class name in a child <class> element of <interceptors>. as in Approach 2 below

Follows an example:

First mandatory step is the interceptor binding:

@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Loggable {
}

Second mandatory step is the Intercepting Class:

@Interceptor
@Loggable
public class LoggingInterceptor {

    @AroundInvoke
    public Object logMethodEntry(InvocationContext ctx) throws Exception{
        System.out.println("In LoggingInterceptor..................... before method call");
        Object returnMe = ctx.proceed();
        System.out.println("In LoggingInterceptor..................... after method call");
        return returnMe;
    }
}

Third step can be achieved using either one of the following approaches

Approach 1, an empty beans.xml will do the job

@Stateless
@Interceptors(LoggingInterceptor.class)     //class interception
public class Displayer implements DisplayerLocal {

    @Override
    //@Interceptors(LoggingInterceptor.class)  //method interception
    public void displayHi() {
        System.out.println(".....Hi there............");
    }
}

Approach 2, needs the beans.xml as follows

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <interceptors>
        <class>com.companyname.LoggingInterceptor</class>
    </interceptors>
</beans>

Then the intercepted class:

@Stateless
@Loggable       //class interception
public class Displayer implements DisplayerLocal {

    @Override
    //@Loggable      //method interception
    public void displayHi() {
        System.out.println(".....Hi there............");
    }
}
Millda answered 1/12, 2013 at 2:25 Comment(2)
We migrated an application to Java 11 and "Approach 1 - empty beans.xml" does not work anymore (on TomEE & Wildfly). We switched to Approach 2 that works fine.Ecstatics
Can i create the annotation, class and interceptor in a simple java project and run with a main method and would it still work? I am doing that, creating the intercepted class and adding a main method to it, and running it, but it doesn't call the interceptor method.Booted
A
1

Interceptors and decorators are enabled from 1.1 version by default. See the highlights of the new CDI spec.

Antigua answered 15/10, 2013 at 7:11 Comment(1)
I have to say that I disagree with your answer. Please see my update for why.Clostridium

© 2022 - 2024 — McMap. All rights reserved.