Abhishek Kumar
Abhishek Kumar

Reputation: 71

java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.$JaCoCo with Java11 and Jacoco 0.8.5

I am getting following error while running a test project in Jenkins

Caused by: java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.$JaCoCo. (java.lang.$JaCoCo is in module java.base of loader 'bootstrap')

Jacoco is defined in the parent pom and the current test pom with different goals.

parent-pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.5</version>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.13</version>
        </dependency>
      </dependencies>
      <executions>
        <execution>
          <id>validate-headless</id>
          <phase>validate</phase>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
          <configuration>
            <skip>true</skip>
            <propertyName>failsafe.argLine</propertyName>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

test-project-pom.xml

<properties>
  <maven.repo.local>${user.home}/.m2/repository</maven.repo.local>
  <itCoverageAgent>-javaagent:${maven.repo.local}/org/jacoco/org.jacoco.agent/0.8.5/org.jacoco.agent-0.8.5-runtime.jar=destfile=${basedir}/target/jacoco-it.exec</itCoverageAgent>
</properties>

<build>
  <plugins>
    <plugin>
      <artifactId>maven-failsafe-plugin</artifactId>
      <configuration>
        <argLine>${failsafe.argLine} ${itCoverageAgent}</argLine>
        <testFailureIgnore>true</testFailureIgnore>
        <reuseForks>true</reuseForks>
      </configuration>
    </plugin>
  </plugins>
</build>

<profiles>
  <profile>
    <id>coverage</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.jacoco</groupId>
          <artifactId>jacoco-maven-plugin</artifactId>
          <version>0.8.5</version>
          <executions>
            <execution>
              <id>prepare-agent-unit</id>
              <goals>
                <goal>prepare-agent</goal>
              </goals>
            </execution>
            <execution>
              <id>prepare-agent-integration</id>
              <goals>
                <goal>prepare-agent-integration</goal>
              </goals>
              <configuration>
                <propertyName>itCoverageAgent</propertyName>
              </configuration>
            </execution>
            <execution>
              <id>report-unit</id>
              <goals>
                <goal>report</goal>
              </goals>
            </execution>
            <execution>
              <id>report-integration</id>
              <goals>
                <goal>report-integration</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

If ${itCoverageAgent} is removed from <argLine> in test-project-pom.xml it works fine. How do we execute different goals from parent-pom and test-project-pom for the same version of Jacoco ?

Upvotes: 6

Views: 6191

Answers (1)

Sean Mickey
Sean Mickey

Reputation: 7716

When you fail at runtime with a java.lang.LinkageError after building with Maven, it's usually an indication that different versions of the same dependency are getting loaded into the JVM. This type of conflict can arise when one of the other dependency entries in your POM has a transitive dependency on a different version of the same Java library or Java class.

You can use the Maven Dependency Plugin to generate a detailed outline of your dependencies, along with all of their transitive dependencies, by running the following command at the root of your project:

mvn dependency:tree

The output is extremely helpful, but it is an exhaustive dependency list, and can sometimes end up being too much of a good thing. If that's true for your project, there is an includes option that may be used to filter the output so that it's focused on a specific dependency or group of dependencies. As an example, you might use it is follows, with an asterisk ('*') wildcard to focus on just Jacoco dependencies:

mvn dependency:tree -Dincludes=org.jacoco.*

The includes option allows multiple filter clauses, separated by a comma (','), and also supports multiple levels of Maven dependency filtering, using the following format structure:

[groupId]:[artifactId]:[type]:[version]

You can find more reference material and documentation on the Maven Dependency Plugin's Filtering the dependency tree web page.

If you do find that you have a transitive dependency that's causing a conflict, the issue can usually be resolved by adding an <exclusions> entry within the definition of the dependency that's causing the problem:

<dependency>
  <groupId>org.open.source.library</groupId>
  <artifactId>problematic-artifact</artifactId>
  <scope>provided</scope>
  <exclusions>
    <exclusion>
      <groupId>org.jacoco</groupId>
      <artifactId>conflicting-transitive-artifact</artifactId>
    </exclusion>
  </exclusions>
</dependency>

This maintains your desired dependency but excludes resolution of the transitive dependency that is creating the conflict, and will resolve the runtime linkage error.


Actually, I don't believe your root problem is a dependency version mismatch; I think your issue is a build plugin configuration collision.

The default build plugin configuration handling in Maven will automatically propagate all plugin configuration defined in a parent pom down to the child poms - which is usually exactly what you want.

But in your case, it's ruining your build. There is however, a simple way for you to declare what is essentially an exclusion -- it's just that you want to exclude build plugin config inheritance rather than build dependencies. You can turn off the customary plugin config propagation using the: <inherited> tag as shown here:

<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.5</version>
            <inherited>false</inherited>
            <!-- Additional build lifecycle goals,
                   plugin configuration entries, and
                      plugin execution definitions: ...
                                              -->
        </plugin>
     </plugins
 </build>

Upvotes: 3

Related Questions