57

I'm trying to run exec-maven-plugin's exec:java goal on a simple two-module project where one module depends on the other. So far I can't find a configuration that works. Here's a boiled-down test case:

+ exec-multi-module-test/
    + pom.xml
    + module1/
        + pom.xml
        + src/
            + main/
                + java/
                    + HelloPrinter.java
    + module2/
        + pom.xml
        + src/
            + main/
                + java/
                    + MyMain.java

Here's the parent pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mkscrg.sandbox</groupId>
    <artifactId>exec-multi-module-test</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>module1</module>
        <module>module2</module>
    </modules>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
            </plugin>
        </plugins>
    </build>
</project>

module1's pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>exec-multi-module-test</artifactId>
        <groupId>com.mkscrg.sandbox</groupId>
        <version>1.0</version>
    </parent>

    <artifactId>module1</artifactId>
</project>

module2's pom: 4.0.0

    <parent>
        <artifactId>exec-multi-module-test</artifactId>
        <groupId>com.mkscrg.sandbox</groupId>
        <version>1.0</version>
    </parent>

    <artifactId>module2</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.mkscrg.sandbox</groupId>
            <artifactId>module1</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

This project compiles successfully from the top, but running mvn exec:java -Dexec.mainClass=myMain fails:

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] exec-multi-module-test
[INFO] module1
[INFO] module2
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building exec-multi-module-test 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) @ exec-multi-module-test >>>
[INFO] 
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) @ exec-multi-module-test <<<
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ exec-multi-module-test ---
[WARNING] 
java.lang.ClassNotFoundException: MyMain
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:285)
        at java.lang.Thread.run(Thread.java:680)
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] exec-multi-module-test ............................ FAILURE [0.363s]
[INFO] module1 ........................................... SKIPPED
[INFO] module2 ........................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.566s
[INFO] Finished at: Mon Jun 18 14:11:54 PDT 2012
[INFO] Final Memory: 3M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:java (default-cli) on project exec-multi-module-test: An exception occured while executing the Java class. MyMain -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

What's the right way to configure this project to allow exec:java to see MyMain?

EDIT: Here's a gist if you'd like to try this yourself: https://gist.github.com/2950830

EDIT: Clarification: I know it's possible to mvn install and then either run exec:java from module2's directory or use the -pl flag from the top. However, I'd like to avoid running mvn install. It shouldn't be necessary to modify my local repository in order to run this goal in a multi-module project. Just as mvn compile "just works" with a multi-module project, so should other goals/phases.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Mike Craig
  • 1,677
  • 1
  • 13
  • 22
  • 1
    This seems to be common enough that [Maven 4 will allow this to just work](https://maarten.mulders.it/2020/11/whats-new-in-maven-4/#root-reactor-aware-subfolder-builds). Maven 4 is currently in alpha, so this can't be used yet. But out of curiosity, I cloned the current development version from the github repo, built it and tried it, and it does work. – blutorange Apr 07 '22 at 18:16
  • `Maven 4 is currently in alpha` I have to say it's not released in any way currently. It is under development correct... – khmarbaise Aug 06 '22 at 09:02
  • No chance that will ever work in maven: https://issues.apache.org/jira/browse/MNG-7527, my solution: https://stackoverflow.com/questions/73255826/executing-individual-maven-plugin-goals-in-multi-module-project – Andrey B. Panfilov Aug 20 '22 at 10:02

3 Answers3

53

Goals in a multi-module project, when run from the parent, will run against all modules. I don't think that's what you want. You can try:

mvn exec:java -pl module2 -Dexec.mainClass=MyMain

That might work? More info:

However, I think it's more intuitive to change directory to the sub-module containing the executable before running it.

Community
  • 1
  • 1
kaliatech
  • 17,579
  • 5
  • 72
  • 84
  • 18
    This (and `cd`ing to the submodule) only work if you've run `mvn install` from the top. Otherwise it fails because it can't find `module1` in any repository. `mvn compile` successfully resolves the modules even though they're not installed in the local repo. I'm looking for a way to get that behavior with `mvn exec:java`. – Mike Craig Jun 18 '12 at 21:58
  • 1
    Sorry for the confusion; I added a clarification in the question. – Mike Craig Jun 18 '12 at 22:27
  • I don't think it's possible to run exec:java without install unless the maven reactor is invoked. Complicating the issue is that when run from the parent POM, there are no dependencies, so exec:java can't find the main class (much less any dependencies.) And when run from the sub-module, the parent/sibling resolution doesn't take place. I tried a number of ideas, but the only that one that worked was @Raghuram 's answer to bind to a lifecycle goal. – kaliatech Jun 20 '12 at 17:02
  • 7
    @MikeCraig -- this answer doesn't work. Why did you accept it? I think Maven can't do this without "install". SBT can do this, but it has its own heap of issues. – Rich Nov 13 '15 at 05:38
  • 3
    typically you can add the flag `-am` to also make the dependent modules, but this causes the plugin to try to run within that module – matt b Oct 23 '18 at 20:33
  • Unfortunately, I was hoping that `{parent}/config` folder would be included in the classpath where property files are searched, but using this method, it is not. :-( – djangofan Feb 08 '21 at 17:06
  • 4
    This answer is wrong. Only works if there is no dependencies between modules, what is not a typical scenario in multi-module context. Will cause "Could not resolve dependencies" error in all other cases. – Balazs Kelemen Oct 14 '21 at 06:49
12
  • You should bind the exec-maven-plugin to a maven lifecycle goal, say verify.
  • Since you want the plugin to be executed only for module2, define the plugin configurations in the parent pom within pluginManagement. Use the same only in module 2.
  • Then run the following:

mvn verify -Dexec.mainClass=MyMain.

parent pom

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <executions>
                 <execution>
                     <phase>verify</phase>
                     <goals>
                         <goal>java</goal>
                     </goals>
                 </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

module 2

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
Raghuram
  • 51,854
  • 11
  • 110
  • 122
  • I verified this works. Cool! Would it be cleaner to use a special profile for configuring this goal only when running exec:java? Otherwise, the exec will be invoked on any activity that goes through the verify lifecycle. – kaliatech Jun 20 '12 at 17:05
  • @kaliatech. Yes indeed, based on the requirement. – Raghuram Jun 21 '12 at 04:15
  • 2
    @Raghuram - I tried this solution, and it works great for running the verify phase. However, when I try to run `mvn exec:java` maven throws an exception telling me that the parameter 'mainClass' is missing for the parent project (instead of only trying to find the mainclass for the child project). Any ideas what I did wrong? – Tiddo Sep 30 '13 at 12:42
  • 1
    for me this doesn't work. executing the module every time in the verify phase is not necessary in my case. i only need to run it when i manually want to start the application, not automatically every time when i'm compiling/packaging/installing/deploying. – ribi86 Dec 07 '16 at 10:28
6

See this answer for a single-command alternative without mvn install:

https://stackoverflow.com/a/26448447/1235281

By using skip in the parent pom.xml, you can tell Maven to only run exec:java on a specific submodule.

GitHub: https://github.com/Oduig/mavenfiddle

Community
  • 1
  • 1
Jodiug
  • 5,425
  • 6
  • 32
  • 48