ACA Blog

ACA Blog

May 2021


Maven Madness in Liferay Land

Dorien JorissenDorien Jorissen

In this post I want to share how you can use Maven to do 2 important things in a Liferay project: patching and creating a deploy package.

While this way of patching is a very powerful way to modify Liferay in an automated way (no manual WAR/JAR patching) you should use it as sparingly as possible. If possible you should always try to use more conventional ways of modding Liferay, for example using a hook, when possible. But whenever that’s not possible, or like me you don’t really like EXT or extlets, feel free to use the methods described in this post.

While this post will be focused on using Maven as a build tool to achieve the desired result, the concepts and techniques should also apply to other build tools like Ant, Gradle or Buildr (and if you’re not already using a build tool… this might be the moment to start using one).


While it can produce similar results as the Liferay EE patching tool in some respects, the patching described in this section is a slightly different beast. They even can, as you’ll see in the deploy package section, be used together. There are a number of different reasons to use this additional way of patching Liferay:

There are a lot of parts of Liferay that you might want/need to patch:

The portal WAR

Let’s start with the easiest case: patching the Liferay WAR file. What makes this the easiest one is that you can simply use the well known Maven WAR plugin‘s overlay ability to achieve the desired result. For most file types you just need to put them in the correct directory of your module for them to be correctly overlayed:

The Maven XML configuration that is needed for this is pretty simple: you just reference the Liferay WAR as a dependency with a runtime scope. During the build Maven will unpack the WAR and then copy over (aka overlay) everything from src/main and repackage it again.

You can even exclude some of the JARs that are already in the WEB-INF/lib directory, such as the JAI JARs, if your OS already provides them or for some other reason. Excluding a JAR dependency in the configuration section of the Maven WAR plugin and then adding a dependency to your overridden version in pom.xml will make sure your custom overlayed JAR will get added instead of the original one. If you just want to add an additional JAR then you only need to add it as a dependency, e.g. a platform specific Xuggler JAR.

The portal service JAR

The next type of overlay is a JAR overlay. This is slightly more complicated, but can still be accomplished by using a pretty standard Maven plugin: the Maven Dependency plugin. The unpack goal during the prepare-package phase allows us to unpack a JAR to the target directory of our module. We then need to provide the pluging with a list of files we want to exclude so that we can override them with our own. We’ll calculate this list using the Maven Groovy plugin, based on the contents of the src/main/java directory.

The actual magic that calculates the list of exclusions happens in the listfiles.groovy file:

The other Liferay JAR files, like util-java.jar, util-bridges.jar, … or basically any other JAR (e.g.: I patched the PDFBox library in Liferay like this) can be overlayed in a similar way.


The third and most peculiar overlay we might need to do is related to something special Liferay does while hot deploying a WAR. Depending on the contents of the file of your portlet the Liferay deployer will copy one or more JARs (util-bridges.jar, util-java.jar, util-sl4j.jar and/or util-taglib.jar), that are embedded in the /com/liferay/portal/deploy/dependencies folder of portal-impl.jar over to the WEB-INF/lib directory of your deployed module. There are also a bunch of other files, like DTDs, in there, that you might want/need to override, that are also copied over in some cases depending on your configuration.

If you for example had to override util-taglib.jar to fix something, you will not only need to make sure your customized version gets included in the overlayed WAR file, but you’ll also need to put it in the correct location in your overlayed portal-impl.jar that also needs to be included in the overlayed WAR file. For this we’ll again use the Maven Dependency plugin, but instead of just 1 execution that unpacks the JAR we need to add a 2nd execution that uses the copy goal to copy all provided artifactItems (basically dependencies) to the correct location inside of the target directory. So first it will unpack the original contents of the JAR, then overlays it with any custom classes/resources and lastly it will copy over any overlayed libraries.

When I finally figured out how to get the above to work I was like:

woah animated gif

Deploy package

One last special thing we’ll use Maven for is to create what we call a deploy package. A deploy package is basically a ZIP file that contains everything that is needed to do a deploy on a server or even locally on a developer’s machine. While currently there are alternative options for this like Docker we find that at a lot of customers this isn’t always an option. Our deploy package solution will work on just about any Unix based OS as it only uses (Bash) scripting. Some nice additional functionality is possible if your servers have access to some sort of Maven repository like a Nexus or Artifactory, but it isn’t needed per se. If you have access to a repository you only need to put the deploy script on the server and it will download the deploy package for you and install it. If you don’t have access to a repository you’ll need to first download the package yourself and transfer it to the server and then run the script.

Building the package

The packaging of the ZIP is done using the Maven Assembly plugin in the deploy module. The deploy module needs to be last module in your list of modules of your root pom.xml for it to be able to correctly reference all the build artifacts. Because we want to be able to use this package, together with the script described in the next section, to be able to produce a reproduceable deploy, it really needs to contain just about everything and the kitchen sink:

Basically anything you can put in a Maven repository and can reference in your deploy module’s pom.xml can be packaged into the deploy package. If your server environment has access to a Maven repository, some things, like the base Liferay Tomcat bundle and the patching tool, can be left out of the package as they can be downloaded just in time by the deploy script described in the next section.

This deploy module is also an excellent place to create an escrow package which is all the source code, resources and libraries that are needed to recreate a specific version of your portal. How you can do this can be found in an older blog post by me: Creating an escrow package with Maven.

How the actual package is made is defined in the assembly.xml file that is used to configure the Maven Assembly plugin. In this file we define the format of the artifact, ZIP, and where all the dependencies, defined in the module’s pom.xml, need to be put in this ZIP file. In the example you’ll see that:

ou can see that with some simple changes to the assembly.xml you could create additional/other subdirectories containing other sets of configuration files/dependencies to suit your needs.

The deploy script

As this really is just a script it can basically do anything you like and can be easily modified to fit your specific needs, the server environment’s constraints, etc… . The example script you can find on Github does the following actions (in order):

Depending on the actual project we’ve added things like Liquibase upgrades, NewRelic installation & configuration, copying additional libraries to Tomcat’s lib/ext, … or just about anything we needed because the scripting system is so flexible. While it might not be as fancy as Docker and consorts it still accomplishes (except for the OS part) about the same result: a perfectly reproduceable deploy.


While working all this out in Maven I might have had the occasional, but typical, f*ck Maven (╯°□°)╯︵ ┻━┻ moment

monkey shoves laptop

but after figuring out all of this JAR & WAR monkeypatching combined with the deploy package system/script it ended up being quite flexible & powerful and made me one happy code monkey in the end!

happy code monkey

All the example code from this post and more can be found on Github:


1 Comment
Newest Most Voted
Inline Feedbacks
View all comments

[…] a Maven release bundle for the actual Liferay customisations we did: 260 Mb (this bundle is based on a method explained in an earlier post: Maven Madness in Liferay Land) […]