Question

I have an EJB 3 module deployed on my Glassfish 2.1 server.

I'm trying to deploy a second EJB module, which depends on this first module, but the deployment fails with java.lang.NoClassDefFoundError about a class that can be found in the first EJB Module.

What's the best way to solve this dependecy between 2 EJB modules? I want to deploy them separately, and not have them in the same EAR.

More specifically, I have a Dependecy Injection of an EJB from my first EJB Module in one of my EJBs of my second EJB module:

@EJB (name="ejb/FirstEJB")
private FirstEJBRemote ejb;

But during deployment I get NoClassDefFoundError about the class FirstEJBRemote:

Error in annotation processing: java.lang.NoClassDefFoundError: FirstEJBRemote
Was it helpful?

Solution 2

Miljen Mikic has a point about the whole Classloaders loading commonly named classes if they wouldn't be isolated.

But with Glassfish, what you should do in your case is place your First EJB module in the directory glassfish_home/domains/domain1/lib/applibs. Then during deployment of the Second EJB module you can specify that the First EJB module's jar should be loaded for this EJB module that is being deployed.

That's called Application-specific class loading, and here's more about it: http://docs.oracle.com/cd/E19798-01/821-1752/gatej/index.html

OTHER TIPS

To understand why this exception has occurred, there are two things to grasp:

  1. How does one EJB reference another EJB
  2. EJB classloading

Let's first deal with number one, so let's name first EJB (containing FirstEJBRemote class) EJB_A and second EJB (who tries to access EJB_A's method) EJB_B. Not going too deeply into @LocalBean annotations and similar stuff, the only way for EJB_B to access EJB_A's methods is through interface. In other words, EJB_A implements some interface (in your case that is FirstEJBRemote) which EJB_B declares and through injection retrieves an instance of EJB_A. So far, so good.

Next, we have to understand EJB classloaders. Naturally, every external class/library that your application (in this case, EJB) uses in compile-time, has to be available also in the runtime. Otherwise, ClassNotFoundException will be thrown and that is exactly what happened in your case, because EJB_B is using FirstEJBRemote in compile-time:

private FirstEJBRemote ejb;

To provide this external class/library to the EJB in runtime, one has to do something of the following:

  • Put the class/library in the lib directory of the application server
  • Pack the class/library together with EJB
  • Put the class/library in the classpath of EAR containing your EJB

We will ignore third option because you said that you are not interested in EARs. Therefore, you can put FirstEJBRemote interface (in form of .jar file, of course) in lib directory of the Glassfish where it will be available both to EJB_A and EJB_B (thus, you don't have to pack it neither with EJB_A) or you can pack this interface together with EJB_B as well, taking care that it resides in the same package as in EJB_A.

In your comment, you wonder why is this "complicated" procedure needed at all. The answer is quite simple - if EJB classloaders weren't isolated mutually, every class that was deployed with EJB_A will be available to EJB_B. In this particular case, that would be wished behaviour, but imagine what happens when EJB_A includes version1 of some library (logging library, for example), and EJB_B uses this same library, but version2. Both classes would be loaded and you will encounter clash everywhere, ClassCastException etc. (or if you are lucky, EJB_B would "only" be forced to use version1 because that class would be already loaded by classloader).

Finally, an excerpt from Oracle GlassFish 3.1 Guide:

Circumventing Class Loader Isolation

Since each application or individually deployed module class loader universe is isolated, an application or module cannot load classes from another application or module. This prevents two similarly named classes in different applications or modules from interfering with each other.

try this instead

@EJB(lookup ="JNDI_BEAN_NAME")

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top