If you are working with Java projects, you will most likely have to deal with Maven. Maven is a project management tool, used as an industry standard for medium to large scale Java applications. In this post, I will teach you to create production artifacts of multi-module Maven projects using the assembly plugin.
Initial project structure
For the purposes of this article, I will assume a very bare-bones project in Maven. We will have 4 modules:
root, which is the main (container) module,
common, which is used by other modules,
app, the app itself, and
tools. We are not writing any actual code here, so do not worry about the logic. Here is the dependency tree for these modules:
Now, we need to create POM files for these modules. Firstly, the
This is the umbrella module that holds the
tools together. You can see them enumerated on lines 11-15. Another important aspect is the
pom packaging mode on line 9. It is used for modules that contain of other modules. Now, the POM for the
Notice right away the
jar packaging mode on line 10. Since this is a standalone module, it does not need the
pom mode, we will be building a JAR file. On lines 5-9 we define the module as a child of
root, and add some dependencies on lines 15-26.
Lastly, here are POM files for the
These 2 look almost the same. They both compile as JAR files and depend on
common (to show you inter-module dependency resolution).
At this moment, you can run
mvn package in
root and get a JAR file for each of your projects (in
<module name>/target). This is very good, but most large project need more fine-tuning in regards of production artifacts. This is where the
assembly plugin is going to help out.
maven-assembly-plugin is used to assemble all modules into 1 entity, while providing overrides for all aspects of the build (as always, convention over configuration). To make it work, we need to add another module to our project, we will call it
This is, again, a standard POM file, with the
pom packaging mode (since
packaging module does not need a JAR file). Now, to connect the
maven-assembly-plugin, add the following code on line 13:
This is a lot, so let’s go step-by-step. Firstly, we define the desired plugin coordinates on lines 4-6. Then, we set it up to run during the
package build phase on lines 10-13 (it happens when you run
mvn package). Lastly, we specify the
assembly.xml (coming in the next step) file as the assembly descriptor. This is effectively a configuration file for the plugin which describes how do we want our artifact to be built.
Lastly, let’s add the
tools modules as dependencies for
packaging, to make sure Maven builds them before the
Assembly descriptor is an XML file that specifies how the production artifact should be structured. Create a file called
assembly.xml in the
packaging module folder:
This is quite a big file, but I assure you there is nothing confusing going on there. Firstly, one line 3, we set the name for this particular assembly (
production-artifact, in our case). Then, on line 5 we set the
dir. This means the resulting artifact will be a folder with JAR files in it. As an alternative, you can change that to
jar and get one BIG jar file with all resources and dependencies. On lines 7-17 we define the dependencies. We say that (line 9) do not use the artifact from the
packaging module itself, (line 10) put the dependencies in the
shared folder, (11) keep them as JAR files instead of unpacking, and (lines 12-15) exclude the
tools from the dependency list.
On lines 18-30 we define the modules included in this artifact. On line 20 we let the plugin know to discover all modules managed by maven and (line 22-23) include only the
tools ones. We do not specify
common here, because it will be included as a dependency under
7-17. I did this to show you how you can use Maven modules as both means to an end (executable) or a library (dependency). Lastly, on lines 26-27 we say to keep the artifacts as JAR and do not include the dependencies in the JAR files directly. They are stored in a separate folder for a number of reasons: saving space, cutting the startup time, dynamic updates, and so on.
Finally, you can run
mvn package in project root and gaze upon your magnificent production build (under
Thank you for reading, this is my first time writing about Java, I hope you liked it.