8

I have a maven project and I want to use jacoco for code coverage. Here is the relevant section of my pom

          <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.5.201505241946</version>
                <executions>
                    <execution>
                        <id>pre-my-test</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <append>true</append>
                            <destFile>${project.build.directory}/jacoco-it.exec</destFile>
                            <propertyName>failsafeArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-my-test</id>
                        <phase>post-my-test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <dataFile>${project.build.directory}/jacoco-it.exec</dataFile>
                            <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

So I am able to run my tests just fine and also build the project just fine. Then I run

mvn clean verify org.jacoco:jacoco-maven-plugin:prepare-agent

I keep getting errors like

ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.7.5.201505241946:
report (post-my-test) on project my-project: 
An error has occurred in JaCoCo Test report generation. 
Error while creating report: 
Error while analyzing class /path/tp/my/project/target/classes/META-INF/
bundled-dependencies/some-third-party-1-jar-with-dependencies.jar@org/slf4j/event/
EventConstants.class. Can't add different class with same name: 
org/slf4j/event/EventConstants -> [Help 1]

some-third-party-1-jar-with-dependencies.jar is an external dependency that I have. This is an uber/shaded jar. So I thought that some-third-party-1-jar-with-dependencies.jar must also have org.slf4j, hence the conflict. So I made a change to the pom as

            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.5.201505241946</version>
                <configuration>
                    <excludes>
                        <exclude>**/org/slf4j/event/EventConstants.*</exclude>
                    </excludes>
                </configuration>
                <executions>
                    <execution>
                        <id>pre-integration-test</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <append>true</append>
                            <destFile>${project.build.directory}/jacoco-it.exec</destFile>
                            <propertyName>failsafeArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-integration-test</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <dataFile>${project.build.directory}/jacoco-it.exec</dataFile>
                            <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

but I still get the same error. How can I make sure that jacoco ignores all duplicate dependencies? I also tried

<dependency>
            <groupId>some.third.party</groupId>
            <artifactId>some-third-party</artifactId>
            <version>1</version>
            <classifier>jar-with-dependencies</classifier>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

but that did not work. Is it possible to have exclusions from shaded/uber jars?

Moreover, why does jacoco care? Is there any way to fix or ignore these errors? How can I resolve this issue?

Hash
  • 4,647
  • 5
  • 21
  • 39
AbtPst
  • 7,778
  • 17
  • 91
  • 172
  • 1
    Excluding the dependency won't work if it's in the actual uber JAR. Did you try the solution described here: https://stackoverflow.com/questions/9133116/jacoco-test-coverage-how-to-exclude-a-class-inside-jar-from-report ? – Dennis Hunziker May 03 '18 at 20:48
  • thanks, I had not looked at that post. but where do i put ` ` ? – AbtPst May 03 '18 at 21:02
  • i mean under which tag? – AbtPst May 03 '18 at 21:02
  • 1
    Never mind, that only exists in the ant version and you use the actual Maven plugin. Looking at the error messages I'm not quite sure how it'll treat your path as it contains an @ and path within the JAR. I'd try a more general exclusion like `**/event/EventConstants*` or similar option. – Dennis Hunziker May 03 '18 at 21:27
  • thanks, i tried `**/event/EventConstants*` but it did not work – AbtPst May 04 '18 at 14:27
  • See if you find any hint here: https://stackoverflow.com/questions/11673356/jacoco-cant-add-different-class-with-same-name-org-hamcrest-basedescription – AKS May 07 '18 at 18:36

3 Answers3

12

Property excludes of report goal specifies which files should be excluded from analysis during generation of report. In case of /path/tp/my/project/target/classes/META-INF/bundled-dependencies/some-third-party-1-jar-with-dependencies.jar@org/slf4j/event/EventConstants.class file is /path/tp/my/project/target/classes/META-INF/bundled-dependencies/some-third-party-1-jar-with-dependencies.jar , and the rest is about class in JAR file.

Therefore as one of examples of correct configuration:

<configuration>
  <excludes>
    <exclude>META-INF/**</exclude>
  </excludes>
</configuration>

As a proof having 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 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>example</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.1</version>
      </plugin>
    </plugins>
  </build>

</project>

src/main/java/Example.java

public class Example {
}

and src/test/java/ExampleTest.java

public class ExampleTest {
  @org.junit.Test
  public void test() {
  }
}

Execution of

mvn clean jacoco:prepare-agent package
mkdir target/classes/META-INF/
cp ~/.m2/repository/org/slf4j/slf4j-api/1.4.2/slf4j-api-1.4.2.jar target/classes
cp ~/.m2/repository/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar target/classes/META-INF
mvn jacoco:report

will fail with message

Error while analyzing /private/tmp/j/target/classes/slf4j-api-1.4.2.jar@org/slf4j/helpers/BasicMarker.class. Can't add different class with same name: org/slf4j/helpers/BasicMarker

while same execution with pom.xml containing exclusion of META-INF/**

<?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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>example</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.1</version>
        <configuration>
          <excludes>
            <exclude>META-INF/**</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

will succeed.

As a side note: semantic of property excludes of prepare-agent goal is different - it specifies class names (regardless of their on-disk location) that should be excluded from instrumentation during execution of tests.

Godin
  • 9,801
  • 2
  • 39
  • 76
1

I solved the duplication issue by adding <phase>prepare-package</phase> to the report execution task:

<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.5</version>
  <executions>
    <execution>
      <id>prepare-agent</id>
      <goals>
      <goal>prepare-agent</goal>
      </goals>
    </execution>
    <execution>
      <id>report</id>
      <phase>prepare-package</phase>
      <goals>
      <goal>report</goal>
      </goals>
    </execution>
  </executions>
</plugin>
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
0

/** is for traversing into underlying directories and different than * which is a character wild card for names. Avoiding ** can result in undesirable effect.

Smart Coder
  • 1,435
  • 19
  • 19