NoClassDefFoundError in non-OSGi environments is straightforward.
ClassNotFoundException: thrown when looking up a class that isn’t on the classpath or using an invalid name to look up a class that isn’t on the runtime classpath.
NoClassDefFoundError: occurs when a compiled class references another class that isn’t on the runtime classpath.
In OSGi environments, however, there are additional cases where a
NoClassDefFoundError can occur. Here are three:
- The missing class belongs to a module dependency that’s an OSGi module.
- The missing class belongs to a module dependency that’s not an OSGi module.
- The missing class belongs to a global library, either at the Liferay Portal webapp scope or the application server scope.
- The missing class belongs to a Java runtime package.
This tutorial explains how to handle each case.
Case 1: The Missing Class Belongs to an OSGi Module
In this case, there are two possible causes:
The module doesn’t import the class’s package: For a module (or WAB) to consume another module’s exported class, the consuming module must import the exported package that contains the class. To do this, you add an
Import-Packageheader in the consuming module’s
bnd.bndfile. If the consuming module tries to access the class without importing it, a
In the consuming module, make sure you import the correct package. First check the package name. If the package import is correct but you still get the exception or error, the class might no longer exist in the package.
The class no longer exists in the imported package: In OSGi runtime environments, modules can change and come and go. If you reference another module’s class that its developer removed, a
ClassNotFoundExceptionoccurs. Semantic Versioning guards against this scenario: removing a class from an exported package constitutes a new major version for that package. Neglecting to increment the package’s major version breaks dependent modules.
For example, say a module that consumes the class
com.foo.Barspecifies the package import
com.foo;version=[1.0.0, 2.0.0). The module uses
1.0.0up to (but not including)
2.0.0. The first part of the version number (the
1.0.0) represents the major version. The consuming module doesn’t expect any major breaking changes, like a class removal. Removing
com.foowithout incrementing the package to a new major version (e.g.,
2.0.0) causes a
NoClassDefFoundErrorwhen other modules look up or reference that class.
You have these options since the class no longer exists in the package:
- Adapt to the new API. To learn how to do this, read the package’s/module’s Javadoc, release notes, and or formal documentation. You can also ask the author, or search forums.
- Revert to the module version you used previously. Deployed module versions reside in
[Liferay_Home]/osgi/. For details, see Backing up Liferay Installations.
Do what you think is best to get your module working properly.
Now you know how to resolve common situations involving
NoClassDefFoundError. For additional information on
NoClassDefFoundError, see OSGi Enroute’s article What is NoClassDefFoundError?.
Case 2: The Missing Class Doesn’t Belong to an OSGi Module
In this case, you have two options:
Convert the dependency into an OSGi module so it can export the missing class. Converting a non-OSGi
JARfile dependency into an OSGi module that you can deploy alongside your application is the ideal solution, so it should be your first choice.
Embed the dependency in your module by embedding the dependency
JARfile’s packages as private packages in your module. If you want to embed a non-OSGi
JARfile in your application, see the tutorial Adding Third Party Libraries to a Module.
Case 3: The Missing Class Belongs to a Global Library
In this case, you can configure Liferay Portal so the OSGi system module exports the missing class’s package. Then your module can import it. You should NOT, however, undertake this lightly. If Liferay intended to make a global library available for use by developers, the system module would already export this library! Still, if you must access a global library that’s not currently exported and can’t think of any other solution, you can consider adding the required package for export by the system module. There are two ways to do this:
portal-ext.propertiesfile, use the property
module.framework.system.packages.extrato specify the packages to export.
If the package you need is from a Liferay Portal JAR, you might be able to add the module to the list of exported packages in
META-INF/system.packages.extra.bndfile. Try this option only if the first option doesn’t work.
If the package you need is from a Liferay Portal module, (i.e., it’s NOT from a global library), you can add the package to that module’s
bnd.bnd exports. You should NOT, however, undertake this lightly. The package would already be be exported if Liferay intended for it to be available.
Case 4: The Missing Class Belongs to a Java Runtime Package
In this case, the class belongs to Java’s
rt.jar but the package isn’t specified in the OSGi Framework’s boot delegation list.
java.* packages are the only ones available on the classpath automatically; other packages must be specified in the boot delegation list to get on the classpath.
Here’s how to add packages to the boot delegation list:
- In a
portal-ext.propertiesfile, override portal property
org.osgi.framework.bootdelegation. Preserve the property’s current list.
- Add the missing package to the list.