Cannot use jacoco JVM args and surefire JVM args together in maven
jacoco, maven, maven-surefire-plugin
Solution
Since the `jacoco-maven-plugin:prepare-agent` goal executes before the maven-surefire-plugin, try adding the `${argLine}` variable into the `argLine` value set by the maven-surefire-plugin.
Example:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>-server -ea -XX:MaxPermSize=256m -Xmx4g -XX:-UseSplitVerifier ${argLine}</argLine>
</configuration>
</plugin>
I had the same problem and this solution worked for me, without any need to reconfigure other sections of the POM.
Problem
I am using maven with the jacoco plugin to generate code coverage metrics. I am having some difficulty in configuring the surefire plugin with the java options required by the jacoco plugin. I've seen some answers about this already on Stack Overflow but something is not working for me. I have a multi-module project, and one of my modules configures the surefire plugin as follows: `foo/pom.xml`: ``` <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <argLine>-XX:MaxPermSize=512m</argLine> </configuration> </plugin> </plugins> ``` This works as expected. Now I want to incorporate jacoco to get code coverage metrics, so I added a CodeCoverage profile that handles all the jacoco configuration: `parent/pom.xml`: ``` <profile> <id>CodeCoverage</id> <build> <pluginManagement> <plugins> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <executions> <execution> <id>jacoco-initialize</id> <goals><goal>prepare-agent</goal></goals> <configuration> <propertyName>surefire.argLine</propertyName> </configuration> ... </execution> <executions> </plugin> </plugins> </pluginManagement> </build> </profile> ``` It is seen here that if the CodeCoverage profile is specified, then the jacoco plugin is configured to use the `surefire.argLine` property, and that property is used to configure the `argLine` for the surefire plugin. I then updated the pom.xml file for the foo module to use the `surefire.argLine` property generated by the jacoco plugin: `foo/pom.xml`: ``` <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine> </configuration> </plugin> </plugins> ``` This approach is specified in the jacoco plugin documentation (see [1]). When I build the foo module with the CodeCoverage profile, I see the following: ``` [foo] $ mvn clean install -X -PCodeCoverage ... [INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo --- [INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\foo\\\target\\coverage-reports\\jacoco-ut.exec ... [DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator --> [DEBUG] (s) argLine = -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec -XX:MaxPermSize=512m ... [INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo --- [INFO] Analyzed bundle 'Foo' with 59 classes` ``` So the jacoco plugin is executed, a `surefire.argLine` property is created, the `argLine` for the surefire plugin uses the `surefire.argLine` property and the local `MaxPermSize` argument, and a `target\code-coverage\jacoc-ut-exec` file is generated, as expected. However, if I do not use the CodeCoverage profile, then I get an error, because the `${surefire.argLine}` property (used in `foo/pom.xml`) is not created by the jacoco plugin, and is not defined anywhere: ``` [foo] $ mvn clean install -X ... [DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator --> [DEBUG] (s) argLine = ${surefire.argLine} -XX:MaxPermSize=512m ... Error: Could not find or load main class ${surefire.argLine}` ``` Sinec the jacoco plugin was not invoked, there's no `surefire.argLine` property created, hence the error. So, I go back to the `parent/pom.xml` and create this property, with no initial value: `parent/pom.xml`: ``` <properties> <surefire.argLine></surefire.argLine> </properties> ``` Now when I build the foo module without using the CodeCoverage profile, I get no errors: ``` [foo] $ mvn clean install -X ... [DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator --> [DEBUG] (s) argLine = -XX:MaxPermSize=512m ... [INFO] BUILD SUCCESS` ``` The surefire argline is now correct (using the empty `surefire.argLine` property) and there is no `target\code-coverage` directory, as expected. So now I go back to generating code metrics, using the CodeCoverage profile: ``` [foo] $ mvn clean install -X -PCodeCoverage ... [INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo --- [INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec ... [DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator --> [DEBUG] (s) argLine = -XX:MaxPermSize=512m ... [INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo --- [INFO] Skipping JaCoCo execution due to missing execution data file:...\foo\target\coverage-reports\jacoco-ut.exec ``` It can be observed here that the jacoco plugin is invoked and sets the `surefire.argLine` property, but the `surefire.argLine` property with the empty value defined in the `parent/pom.xml` file is actually used to create the argline for the surefire plugin. As a result, there is no `jacoco-ut.exec` file, and no `target\code-coverage` directory, when I use the CodeCoverage profile. I'm not sure what I am doing wrong here. I'm declaring an `argLine` property as suggested by the jacoco documentation, and using it whenever a surefire plugin needs to specify additional argument. Other answers on Stack Overflow suggest creating a property with the same name as the jacoco argLine property to handle the case when jacoco is not invoked. Any suggestions? edit Maybe one solution is to explicitly declare the `surefire.argLine` property in the CodeCoverage profile, and forget about using the `argLine` of the jacoco plugin: ``` <profile> <id>CodeCoverage</id> <properties> <surefire.argLine>-javaagent:${jacoco.agent.jar}=destfile=${jacoco.report.path}</surefire.argLine> </properties> <build> <plugins> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <executions> <execution> <id>jacoco-initialize</id> <goals> <goal>prepare-agent</goal> </goals> <!-- no longer specifying 'argLine' for jacoco plugin ... --> </execution> <executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <!-- ... instead the arg line is configured explicitly for surefire plugin. --> <argLine>${surefire.argLine}</argLine> </configuration> </plugin> </plugins> </plugin> </build> ``` This will create the surefire.argLine property to use the java agent required by the jacoco plugin, and configure the surefire plugin to use that property for its JVM args. The jacoco plugin will now create a argLine property, but this will be ignored. It's not an elegant solution (since I'm making assumptions about how the jacoco plugin works, and this may change in a future version). edit The `jacoco.agent.jar` property must also be set, by pointing to its location in the local repository (not sure if this is robust) or by using the dependency plugin to copy the jacoco agent jar to the local build directory: ``` <profile> <id>CodeCoverage</id> <properties> <jacoco.agent.jar>${project.build.directory}/jacoco-agent.jar</jacoco.agent.jar> ... </project> <build> ... <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>download-jacoco-agent</id> <phase>process-test-resources</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>org.jacoco</groupId> <artifactId>org.jacoco.agent</artifactId> <version>${jacoco.version}</version> <classifier>runtime</classifier> <outputDirectory>${project.build.directory}</outputDirectory> <destFileName>jacoco-agent.jar</destFileName> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> ``` edit Not sure if using the dependency plugin is the right approach, or pointing to the jacoco agent artifact in the local repository: ``` <profile> <id>CodeCoverage</id> <properties> <jacoco.agent.jar>${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar</jacoco.agent.jar> </properties> ... </profile> ``` This is simpler, and does not require copying an artifact to the local build directory, but is fragile: changes in the repository layout will break this. [1] http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html