Many Java projects are built with Maven, and it is common for these projects to be structured as multi-module projects to allow for clean code separation and better reuse. It’s well documented how to use the Maven CLI options -am
in conjunction with -pl <project-dir-list>
in order to run Maven commands like compile
and test
within a single submodule, while still taking into account the other submodules in the project needed as dependencies. Meanwhile, we can execute a Java class using the exec:java
command. But how do we get that to work in a multi-module project?
There hasn’t been a definitely way of achieving this goal that is well-publicized and thoroughly described. I think I have a solution, and this post is just brining attention to that solution for the benefit of others. I documented the solution in detail in the Github repo for a project that was set up as a multi-module Maven project, which has a PR implementing it. Here, below, is just a brief overview.
Beyond the standard -am -pl <project-dir-list>
that is typical for a multi-module project, there were 2 parts that of the solution that were needed together:
- Configure exec:java to prevent it running at the root, and instead only run it in the submodule(s) necessary. This happens in the root pom.xml and the pom.xml’s in the submodules of interest
- Add the
compile
target before theexec:java
target within the CLI command string so that submodule dependency code gets compiled and thus made available to the submodule of interest
This works for Maven 3, and Maven 4 is not available, and from the sounds of it, Maven 4 will not solve this problem out-of-the-box either.
The above provides a way to have a single CLI command with the desired effect.
There may be other ways to achieve the desired outcome, but I did not explore them. One idea is to achieve the same effect by 2 CLI invocations rather than 1 all-in-one. Those 2 commands might look like, in order:
- Compile the submodule and its dependency submodules of interest:
mvn compile -am -pl <project-dir>
- Execute the single class file of interest from its submodule, and we must and (perhaps) can ignore any source code dependency from other submodules by omitting
-am
:mvn exec:java -pl <project-dir> -Dexec.mainClass="..." -Dexec.args="..."