We have a multi-module Java Maven project structured like this:
parent
├── child-1
├── child-2
└── common
There is no code in the parent, and the code and tests are mostly in common.
We want to generate a code coverage report per submodule (not a single global report for the entire project).
According to the SonarQube documentation for Java test coverage, we just need to add this configuration to the parent POM:
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
When we run
mvn clean verify
in the parent directory, we see this in the logs:
[INFO] — jacoco:0.8.13:prepare-agent (prepare-agent) @ my-service —
[INFO] argLine set to -javaagent:C:\Users\me\.m2\repository\org\jacoco\org.jacoco.agent\0.8.13\org.jacoco.agent-0.8.13-runtime.jar=destfile=C:\Users\me\dev\my-service\target\jacoco.exec
[INFO] --- jacoco:0.8.13:report (report) @ my-service ---^M
[INFO] Skipping JaCoCo execution due to missing execution data file.^M
However, no output is generated—no XML files, no .exec files, and no target/site/jacoco directories in the parent or any submodules.
The Sonar docs say:
"By default, the generated report will be saved under target/site/jacoco/jacoco.xml"
But this directory doesn't exist after running the commands.
Here is where it gets different, if we run
mvn clean verify sonar:sonar
we do not see the above jacoco:0.8.13:prepare-agent in the output.
If push these changes to the PR, the Bitbucket Sonar pipeline re-runs, and we see this in the output:
[INFO] argLine set to -javaagent:/root/.m2/repository/org/jacoco/org.jacoco.agent/0.8.13/org.jacoco.agent-0.8.13-runtime.jar=destfile=/opt/atlassian/pipelines/agent/build/target/jacoco.exec
[INFO] --- jacoco:0.8.13:report (report) @ my-service ---
[INFO] Skipping JaCoCo execution due to missing execution data file.
If we check a submodule's target directory, we see:
d----- 15/05/2025 14:34 classes
d----- 17/06/2025 15:15 generated-sources
d----- 17/06/2025 15:15 generated-test-sources
d----- 29/05/2025 17:35 maven-archiver
d----- 29/05/2025 17:35 maven-status
d----- 17/06/2025 15:16 surefire-reports
d----- 29/05/2025 17:35 test-classes
There’s no jacoco.exec file or coverage output. The parent module also doesn't have a target directory.
We expected Sonar to handle code coverage using the config from the documentation, but it's not working.
We also tried adding the phase (but didn't help):
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<phase>verify</phase>
NOTE: we don't have any configuration in parent or child poms for surefire. The tests run fine without it.
Here is our full parent/pom.xml:
<?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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.4</version>
</parent>
<properties>
<sonar.organization>xxx</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
<groupId>com.xx.xx</groupId>
<artifactId>xx-xx-service</artifactId>
<version>1.0-SNAPSHOT</version>
<name>xx-xx-service</name>
<description>xx service</description>
<packaging>pom</packaging>
<modules>
<module>xx-common</module>
<module>xx-api</module>
<module>xx-schedule</module>
</modules>
<profiles>
<profile>
<id>coverage</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
We also tried running:
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Pcoverage
Still no Jacoco output.
I tried setting output to file in the config:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<configuration>
<output>file</output>
<append>true</append>
</configuration>
What can I try next? We’re new to Jacoco and thought Sonar would handle the coverage reporting, but it doesn't seem to be working using the documentation’s configuration.