NoClassDefFoundError are common, well known
ClassNotFoundExceptionis 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.
NoClassDefFoundErroroccurs 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:
- 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 DXP webapp scope or the application server scope.
- The missing class belongs to a Java runtime package.
This tutorial explains how to handle each case.
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 the package, a
Check the package name and make sure the consuming module imports the right package. If the 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: Modules are changed frequently in OSGi runtime environments. 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 limited options when 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
see OSGi Enroute’s article
What is NoClassDefFoundError?.
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.
In this case, you can configure Liferay DXP 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! Proceed only if you have no other solution, and watch out for unintended consequences. There are two ways to export the package:
portal-ext.propertiesfile, use the property
module.framework.system.packages.extrato specify the packages to export. Preserve the property’s current list.
If the package you need is from a Liferay DXP 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 DXP module, (i.e., it’s NOT
from a global library), you can add the package to that module’s
exports. You should NOT, however, undertake this lightly. The package would
already be exported if Liferay intended for it to be available.
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.
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:
portal-ext.propertiesfile, override portal property
org.osgi.framework.bootdelegation. Preserve the property’s current list.
Add the missing package to the list.