Search code examples
mavenmaven-exec-plugin

Maven: How to execute a dependency in a forked JVM?


Using maven-exec-plugin and a java goal I execute a jar program that validates some files in my project. When the validation fails, it calls System.exit to return a non zero return code.

The problem is that it executes in the same JVM as Maven, so when it calls exit, the processing stops since it does not fork.

I configured it to execute with maven-exec-plugin and a java goal (like in here ). The execute jar is in my Nexus repository, so I want to download it as a dependency in my pom.xml.

A very nice feature of configuring the maven-exec-plugin dependency is that it downloads the jar and all its dependencies, so it isn't necessary to use maven assembly plugin to include all jars in the executable.

How do I configure my pom.xml to execute a jar dependency and correctly stop when it fails?


Solution

  • I solved my problem. Basically, instead of using the java goal, I must use the exec goal, and run the java executable. The code below sets the classpath and the class with the main method.

    This solution using the pom.xml and a Nexus repository has a lot of advantages over just handling a jar file for my users:

    • No need to install anything in the machine that will run it, be it a developer machine or a continuous integration one.
    • The validation tool developer can release new versions and it will be automatically updated.
    • The developer can turn it off with a simple parameter.
    • Also solves the original problem: the validation tool will execute in a separate process, so the maven process won't abort when it calls System.exit.

    Here is a commented pom.xml:

    <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.company</groupId>
        <artifactId>yourId</artifactId>
        <version>1.0</version>
        <properties>
                    <!-- 
                    Skip the validation executing maven setting the parameter below
                    mvn integration-test  -Dvalidation.skip
                    -->
    
            <validation.skip>false</validation.skip>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.6.0</version>
    
                    <executions>
                        <execution>
                            <id>MyValidator</id>
                            <phase>integration-test</phase> <!-- you can associate to any maven phase -->
                            <goals>
                                <goal>exec</goal> <!-- forces execution in another process -->
                            </goals>
                        </execution>
                    </executions>
    
                    <configuration>
                        <executable>java</executable> <!-- java must be in your PATH -->
                        <includeProjectDependencies>false</includeProjectDependencies>
                        <includePluginDependencies>false</includePluginDependencies>
                        <skip>${validation.skip}</skip>
                        <arguments>
                            <argument>-classpath</argument> 
                            <classpath/> <!-- will include your class path -->
                            <mainClass>com.company.yourpackage.AppMain</mainClass> <!-- the class that has your main file -->
                            <argument>argument.xml</argument> <!-- any argument for your executable -->
                        </arguments>
                    </configuration>
    
                </plugin>
            </plugins>
        </build>
        <dependencies>
            <dependency>
                <!-- Specify your executable jar here -->
                <groupId>com.company.validator</groupId>
                <artifactId>validatorId</artifactId>
                <version>RELEASE</version> <!-- you can specify a fixed version here -->
                <type>jar</type>
            </dependency>
        </dependencies>
    </project>
    

    You can run more than one executable passing its id: mvn exec:exec@MyValidator