Blogs
Later versions of Liferay are using OSGi Core R7, and this can impact Java package imports...
Just a quick one today...
A community member reported getting an exception during module deployment:
INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][AutoDeployDir:238] Processing com.liferay.report.jar ERROR [fileinstall-directory-watcher][DirectoryWatcher:1195] Unable to start bundle: file:/D:/worksp/liferay-ce-portal-7.4.3.8-ga8/osgi/modules/com.liferay.report.jar com.liferay.portal.kernel.log.LogSanitizerException: org.osgi.framework.BundleException: Could not resolve module: com.liferay.report [1555]_ Unresolved requirement: Import-Package: java.util.Map_ [Sanitized] at org.eclipse.osgi.container.Module.start(Module.java:444) ~[org.eclipse.osgi.jar:?] at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:428) ~[org.eclipse.osgi.jar:?] at com.liferay.portal.file.install.internal.DirectoryWatcher. _startBundle(DirectoryWatcher.java:1178) [bundleFile:?] at com.liferay.portal.file.install.internal.DirectoryWatcher. _startBundles(DirectoryWatcher.java:1211) [bundleFile:?] at com.liferay.portal.file.install.internal.DirectoryWatcher. _startAllBundles(DirectoryWatcher.java:1156) [bundleFile:?] at com.liferay.portal.file.install.internal.DirectoryWatcher. _process(DirectoryWatcher.java:1068) [bundleFile:?] at com.liferay.portal.file.install.internal.DirectoryWatcher. run(DirectoryWatcher.java:250) [bundleFile:?]
Although a lot is in this error, the important part is
the Unresolved requirement: Import-Package:
java.util.Map
portion.
Kind of weird, right? The module is failing because it cannot
find the java.util.Map
package. Obviously, because
Map
is a class, not a package.
So the question was how was the code referencing
Map
such that BND was considering it to be a package?
Long story short, they were importing
java.util.Map.Entry
in a JSP file. In this form, BND was
interpreting Map
as part of the package and
Entry
was the class...
So there were two solutions to this problem:
1. Change the import. When you import
java.util.Map
, you will automatically get the
Entry
class, although in some cases you may need to
refer to it as Map.Entry
. Not a big deal, super easy to
change and use in this way.
2. Add a new directive to the bnd.bnd
file...
So this second option I didn't know about until I talked to my friend Ray Auge...
In later versions of Liferay, OSGi Core R7 is used, and there
was a change to BND to start including Java packages in the
Import-Package
declaration. This change would allow for
identifying cases where a Java package is being used but maybe not
available in the Java runtime. Consider, for example, a Java 11 module
that uses classes from the java.lang.module
package; by
adding java.lang.module
to the
Import-Package
declaration, the module would be flagged
by OSGi in an environment where the java.lang.module
package was not available.
So while this might be good generally, it is probably not a problem that we as Liferay developers will contend with...
And besides, if importing java.util.Map.Entry
causes us some deployment headaches, this feature may not be worth it...
Fortunately for us, there is a new BND directive that you can
add into your bnd.bnd
file:
-noimportjava:
true
This directive will have BND exclude any
java.*
imports in the Import-Package
declaration.
By adding this directive, the community member can continue to
import java.util.Map.Entry
and leave the rest of the code
unchanged (may be necessary in cases where you might not be able to
change the code for one reason or another).
In fact, there is no harm to adding the -noimportjava:
true
directive to all of your bnd.bnd
files, so
feel free to do so.
You can read more about the -noimportjava
directive
here: https://bnd.bndtools.org/instructions/noimportjava.html