Resolving "internal" dependencies

Resolving "internal" dependencies in your OSGi modules

Overview

Sometimes you may need to reference some class from "internal" package of Liferay's OSGi bundle.
But classes under "internal" package are not exposed by Liferay bundles, and thus, can't be used by default.
You can include dependency on that module, for example:
compileOnly group: "com.liferay", name: "com.liferay.asset.publisher.web", version: "3.0.43"
and you'll be able to compile/assemble/deploy your OSGi JAR, but you'll get a runtime error during deployment, like:
org.osgi.framework.BundleException: Could not resolve module: com.lifedev.asset.publisher.portlet.filter [1105]_ Unresolved requirement: Import-Package: com.liferay.asset.publisher.web.internal.util_ [Sanitized] at org.eclipse.osgi.container.Module.start(Module.java:444) at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:428)
saying that package under "internal" can't be resolved.
However, there are a couple of workarounds to fix this. Below are two different approaches.

Including resource to your bundle

You may include class(es) you use in your module in bnd.bnd, sample:
-includeresource: @com.liferay.asset.publisher.web-3.0.43.jar!/com/liferay/asset/publisher/web/internal/util/AssetQueryRule.class
This will include Liferay's class directly to the assmbled JAR:
images/included-jar.png
When you deploy such JAR - you'll not get "Unresolved requirement" error anymore, as your bundle contains that class.
This is similar to "compileInclude" with Gradle, with the exception, that you include only specified classes to your bundle.
Note: use it with caution: this approach will lead to class duplication (in the original Liferay module and in your new one), which may cause ClassLoader issues. To prevent this - use next approach.

Export packages with a Fragment module

If you used JSP Override approach for customizing JSPs - you should be familiar with Fragment modules already.
With a fragment module, you can not only override the JSP you need, but also export the required packages.
For example, if you have a fragment module for asset-publisher-web:
Fragment-Host: com.liferay.asset.publisher.web;bundle-version="3.0.43"
you may also specify the Export-Package in the bnd.bnd of your fragment module:
Export-Package: com.liferay.asset.publisher.web.internal.util
This will make the exported packages publicly available, and you may use it in your modules.
Note: fragment module should be used only for customization (for example, JSP override or additional packages exports). For custom components - use separate OSGi modules.

Comments

  1. Exporting internal packages with fragments was a game changer for me! Thanks!

    ReplyDelete

Post a Comment

Popular posts from this blog

Liferay Search Container Example

Liferay DXP - max upload file size

Liferay Keycloak integration