Don't Overload EJB 3 Lifecycle and Interceptor Methods

Overloading is a natural part of java language. With overloading, we are just declaring multiple, totally separate methods that happen to share the same name. But don't use overloading when it comes to EJB 3 lifecycle and interceptor methods. For example, the following bean and interceptor classes are all wrong:

Invalid EJB 1.
package com.foo.ejb;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;

@Stateless
public class InvalidBean1 implements HelloRemote {
@PostConstruct
private void init() {
System.out.println("InvalidBean1 PostConstruct method called.");
}

public void init(Properties props) {
System.out.println("InvalidBean1 public init(Properties) method, not a PostConstruct method.");
}
To fix it, just rename init(Properties) to init2(Properties), and make sure init method is not overloaded in the current class.

Invalid EJB 2.
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

@Stateless
public class InvalidBean2 implements HelloRemote {
@AroundInvoke
private Object intercept(InvocationContext inv)
throws Exception {
System.out.println("InvalidBean2 AroundInvoke method called.");
return inv.proceed();
}

public void intercept(Properties props) {
System.out.println("InvalidBean2 public intercept(Properties) method, not an AroundInvoke method.");
}
}
To fix it, just rename intercept(Properties) to intercept2(Properties), and make sure intercept method is not overloaded in the current class.

Invalid interceptor class
.
import javax.interceptor.InvocationContext;
import javax.interceptor.AroundInvoke;

public class InvalidInterceptor {
@AroundInvoke
private Object intercept(InvocationContext inv)
throws Exception {
System.out.println("InvalidInterceptor AroundInvoke method called.");
return inv.proceed();
}

public void intercept(Properties props) {
System.out.println("InvalidInterceptor public intercept(Properties) method, not an AroundInvoke method.");
}
}
To fix it, just rename intercept(Properties) to intercept2(Properties), and make sure intercept method is not overloaded in the current class.

What will happen with these invalid apps? Since these overloaded methods are legal in java, so your apps will be able to build, maybe even deploy successfully. But when the EJB is instantiated, EJB container looks for a lifecycle or interceptor method only by name. It may or may not get the correct method, depending on container implementation, operation systems, and other unknown factors.

With JavaEE SDK 5/Glassfish/Sun Java System Application Server 9 on Sparc Solaris 10 , I was able to deploy and run my app successfully, and the correct lifecycle method is found and invoked. With the same appserver on Windows, accessing the EJB will always fail with the following error:
[#|2006-06-23T10:07:11.291-0400|INFO|sun-appserver-pe9.0|javax.enterprise.system.container.ejb|_ThreadID=16;_ThreadName=p: thread-pool-1; w: 3;|EJB5070: Exception creating stateless session bean : [{0}]
java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor$1.run(InterceptorManager.java:601)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:595)
at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(InterceptorManager.java:448)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:204)
at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:546)
at com.sun.ejb.containers.StatelessSessionContainer.access$100(StatelessSessionContainer.java:96)
at com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:746)
at com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:186)
at com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:469)
at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:1566)
at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1148)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:189)
at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:110)
...
It means on Windows, the appserver always gets the wrong, unannotated method by its overloaded name.

This is a bug in the application, not in the appserver. Unfortunately, it's a restriction we have to live with.

Continue to part 2 and part 3

Followers

Pageviews Last 7 Days