Blogs
Introduction
So I wrote https://liferay.dev/blogs/-/blogs/extending-liferay-osgi-modules five years ago targeting Liferay 7.0.
A lot has changed since then. Liferay Gradle Workspace plugin has seen numerous updates. Gradle has seen an update or two as well.
Recently when asked to assist a client who wanted to extend Liferay's Journal Article service, I started by recommending they look at this old blog post for guidance.
However, I was a bit surprised when they came back after giving it a try and reported that the technique described in the blog was not working for them. I shouldn't have been surprised, given the changes that had happened since the post went up 5 years ago.
After reviewing the issue and finding a resolution, I figured it was time to come back and revisit the method for extending Liferay OSGi modules...
The Goal
The goal is usually pretty straight forward - you need to
override a Liferay DXP class that is contained in a jar that is
contained in an LPKG file, you can't replace it using an
@Component
override nor can you extend it because it is
in an internal package.
For these cases, you need a Marketplace Override, or basically a jar to replace Liferay's module jar named in a specific way and dropped into the osgi/marketplace/override directory.
The challenge, of course, is how to build it...
For the current client, they wanted to override the
com.liferay.journal.internal.upgrade.util.JournalArticleImageUpgradeHelper
class from the com.liferay.journal.service module.
What follows is how we did it...
Creating the Module
Again, in a Liferay Workspace, we'll need a basic Gradle-based module.
In the src/main/java directory we created the overriding
com.liferay.journal.internal.upgrade.util.JournalArticleImageUpgradeHelper
class.
Following the old blog, we had the following build.gradle file:
dependencies { compileOnly group: "com.liferay.portal", name: "release.dxp.api" compile group: "com.liferay", name: "com.liferay.journal.service", version: "6.0.72" } jar.archiveName = 'com.liferay.journal.service.jar'
We were targeting Liferay DXP 7.2, and 6.0.72 was the version that was in the FixPack we were building for.
And like the old blog, we also had the following bnd.bnd file:
Bundle-Name: Liferay Journal Service Bundle-SymbolicName: com.liferay.journal.service Bundle-Version: 6.0.72 Liferay-Require-SchemaVersion: 3.4.0 Liferay-Service: true -dsannotations-options: inherit Include-Resource: @com.liferay.journal.service-6.0.72.jar
The Problem
So we followed the old blog and the module built and deployed correctly, but the overriding class was just not being used.
I opened up the built jar and found that the overriding class,
although being compiled as part of the build process, was not being
included correctly in the jar. Actually what I think happened, the
Include-Resource
header was doing just that, it was
exploding and pulling in all of the files from the Liferay jar,
basically replacing the custom one with the legacy one when building
the jar.
So even though my project had files in the right places, they were getting stomped on by the legacy files when the jar was being built.
The Solution
Clearly the Include-Resource
header was causing me
problems. After conferring with my good friend Ray Auge (and per his
guidance), I switched up to a directive in my bnd.bnd file:
Bundle-Name: Liferay Journal Service Bundle-SymbolicName: com.liferay.journal.service Bundle-Version: 6.0.72 Liferay-Require-SchemaVersion: 3.4.0 Liferay-Service: true -dsannotations-options: inherit -includeresource: @com.liferay.journal.service-6.0.72.jar!/!com/liferay/journal/internal/upgrade/util/JournalArticleImageUpgradeHelper.class
So here I've switched from Include-Resource
header
to -includeresource
directive. This directive has
significantly more configuration options on it and is more powerful
than the header itself: https://bnd.bndtools.org/instructions/includeresource.html
Specifically, the include resource directive above reads: "From the exploded com.liferay.journal.service-6.0.72.jar dependency, include all files except excluding the JournalArticleImageUpgradeHelper.class".
The @ sign in front of the jar means it should be exploded and not just injected as-is.
Following the first ! character is the path to include, by using "/" alone we're saying that all files should be included.
The second ! marks the exclusion rule where we have specified the path to the class file that should not be pulled forward.
The documentation page for the -includeresource
directive has lots of other details for different ways you can
structure the arguments to get the outcome you need.
Conclusion
With this new -includeresource
directive in the
bnd.bnd file, when the jar was built almost all of the files from the
legacy jar were included in the new module jar (all except for the
class we didn't want to bring forward), and the custom class was in
the module instead.
The new module jar, when dropped into the osgi/marketplace/override folder, injected the necessary override logic and the desired outcome was achieved.
Switching from the Include-Resource
header to the
-includeresource
directive made all the difference. It's
also notable that at Liferay the engineering team now exclusively uses
the directive (well, you can see the header used in test modules, but
otherwise it is all the directive).
Hopefully this will come in handy in case you also need to build a Liferay override module.