javajava-ee-8glassfish-5cdi-2.0

Why CDI interceptor injected in a singleton is not called by the Glassfish 5.1 container


The CDI interceptor that records the method entry and exit in the log file is not being called for the singleton class by the container?

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

Here is the interceptor:

@Interceptor
@Logit
public class RecordIntereceptor implements Serializable {
    private static final long serialVersionUID = -2230122751970857900L;
    public RecordIntereceptor() {
    }
    @AroundInvoke
    public Object logEntryExit(InvocationContext ctx)throws Exception{
        String methodName = ctx.getMethod().getName();
        String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
        Logger logger = Logger.getLogger(declaringClass);
        logger.entering("List Service Intereceptor "+declaringClass, methodName);
        Object result = ctx.proceed();
        logger.exiting("List Service Intereceptor "+declaringClass, methodName);
        return result;
    }
}

Here is a singleton class using the interceptor:

@Logit
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DataLoaderSessionBean {
 @PostConstruct
    public void createData() {
        removeStartupData();
        loadUsers();
        loadParts();
    }
...........
...........
}

Finally the beans.xml:

<?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"
       bean-discovery-mode="annotated">
    <interceptors>
        <class>org.me.jsfproject.intereceptor.RecordIntereceptor</class>
    </interceptors>
</beans>

There is no method entry or exit logs for the method DataLoaderSessionBean.createData() in the log file. Using the debugger, I step through the code and the interceptor is not being called by the container. Although the interceptor works fine for non-singleton classes? Any idea why this is happening?


There seem to be restrictions with Interceptors that have life cycle methods (i.e. @postConstruct) they must be of @Target({TYPE}) so I created an additional new Interceptor interface and a new Interceptor merely for the Singleton class as follow:

@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE})
public @interface LifeCycleLogger {
}

@Interceptor
@LifeCycleLogger

public class LifeCycleIntereceptor implements Serializable {
    private static final long serialVersionUID = -2230122753370857601L;
    public LifeCycleIntereceptor() {
    }
   
    @PostConstruct
    public void logPostConstruct(InvocationContext ctx){
        String methodName = ctx.getMethod().getName();
        String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
        Logger logger = Logger.getLogger(declaringClass);
        logger.entering("Life Cycle Intereceptor "+declaringClass, methodName);
        try {
            ctx.proceed();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "LifeCycle Interceptor Post Construct caught an exception: {0}", e.getMessage());
        }
        
        logger.exiting("Life Cycle Intereceptor "+declaringClass, methodName);
    }
}

I changed the Singleton as follow:

@LifeCycleLogger
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DataLoaderSessionBean{

................
    public DataLoaderSessionBean(){
        
    }

    @PostConstruct
    public void createData() {
        ........
        
    }
............
}

However, there are no entry or exit logs for the createData() method?


Solution

  • As createData() is a lifecycle method of DataLoaderSessionBean it doesn't get captured by the @AroundInvoke annotation.

    To declare a method in the interceptor that captures the @PostConstruct lifecycle call, you have to annotate it with this same annotation:

    @PostConstruct
    public void logPostConstruct(InvocationContext ctx) throws Exception{
        String methodName = ctx.getMethod().getName();
        String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
        Logger logger = Logger.getLogger(declaringClass);
        logger.entering("List Service Intereceptor "+declaringClass, methodName);
        ctx.proceed();
        logger.exiting("List Service Intereceptor "+declaringClass, methodName);
    }