Gradle Multi-Project build with JaCoCo Code Coverage and Spring Boot fails

My apologies, if this is not allowed, I already have posted a detailed version here: https://stackoverflow.com/q/66265413/3469592

Basically, I would like to run JaCoCo coverage on a Gradle multi-project build which uses Spring Boot. So I started with the sample from here Reporting code coverage with JaCoCo Sample and added Spring Boot. The resulting (minimal) project can be found here: GitHub - SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage at 57e57b8bf24ef4208d9a03a361714c916701e599

As soon as I add Spring Boot, when running

./gradlew clean build codeCoverage -stacktrace

I get the following error

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':code-coverage-report:codeCoverageReport'.
        [...]
Caused by: java.io.IOException: Error while analyzing log4j-api-2.13.3.jar@org/apache/logging/log4j/util/ProcessIdUtil.class.
        at org.jacoco.core.analysis.Analyzer.analyzerError(Analyzer.java:162)
        at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:134)
        at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:157)
        at org.jacoco.core.analysis.Analyzer.analyzeAll(Analyzer.java:193)
        at org.jacoco.core.analysis.Analyzer.analyzeZip(Analyzer.java:265)
        at org.jacoco.core.analysis.Analyzer.analyzeAll(Analyzer.java:196)
        at org.jacoco.ant.ReportTask.createBundle(ReportTask.java:573)
        at org.jacoco.ant.ReportTask.createReport(ReportTask.java:545)
        at org.jacoco.ant.ReportTask.execute(ReportTask.java:496)
        ... 251 more
Caused by: java.lang.IllegalStateException: Can't add different class with same name: org/apache/logging/log4j/util/ProcessIdUtil
        at org.jacoco.core.analysis.CoverageBuilder.visitCoverage(CoverageBuilder.java:106)
        at org.jacoco.core.analysis.Analyzer$1.visitEnd(Analyzer.java:99)
        at org.objectweb.asm.ClassVisitor.visitEnd(ClassVisitor.java:378)
        at org.jacoco.core.internal.flow.ClassProbesAdapter.visitEnd(ClassProbesAdapter.java:100)
        at org.objectweb.asm.ClassReader.accept(ClassReader.java:722)
        at org.objectweb.asm.ClassReader.accept(ClassReader.java:401)
        at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:116)
        at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:132)
        ... 258 more

Does anyone have any information on how to fix this error?

Hi,

I’d suggest to use includes and excludes to compute coverage the actual source packages and ignore everything brought by the runtime environment (java, jakartaee, …) or third party dependencies:

tasks.withType(Test) {
    jacoco {
        includes 'org.mycompany.*', 'com.mycompany.*'
    }
}

Hi @Pierre1 ,
thanks for the hint. Unfortunately, this gives me the following error

Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method includes() for arguments [org.mycompany., com.mycompany.] on extension ‘jacoco’ of type org.gradle.testing.jacoco.plugins.JacocoTaskExtension.

Do you have any idea how to fix it?

Hi,

My bad, the correct syntax is:

includes = ['org.mycompany.*', 'com.mycompany.*']

The user guide main page: The JaCoCo Plugin
The API of this extension: JacocoTaskExtension (Gradle API 6.8.2) (there is no includes method, but a setIncludes, hence the need of the = symbol and the brackets to call it)

Hi @Pierre1,
thank you very much for the update. I tried setting this in both the java-conventions as well as the jacoco-aggregation convention plugin (see https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage/compare/Try-Setting-Includes?expand=1 for the exact changes),

tasks.withType(Test) {
    jacoco {
        includes = ['org.gradle.sample.*']
    }
}

but I still get the following error

java.lang.IllegalStateException: Can’t add different class with same name: org/apache/logging/log4j/util/ProcessIdUtil

It seems like the includes cannot be set the way I tried. Maybe I’m missing something very simple/elementary?

Hi,

I pushed a PR on your github project that fixes the error and generate the report.
I’ve reviewed it quite quickly but it seems to be correct so far.

@Pierre1 Thank you very much! This seems to work (i.e., the fix Fix coverage · SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage@cad31bc · GitHub ).

The working example is now here GitHub - SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage.

As I basically directly copied the example from here Reporting code coverage with JaCoCo Sample, do you think it is also something that should be adjusted in the example? I assume the combination of multi-project builds and Spring Boot is not that unusual?

Hi,

Maybe you can try to push a PR on gradle/subprojects/docs/src/samples/java/jvm-multi-project-with-code-coverage at master · gradle/gradle · GitHub
Or raise the issue in gradle issue tracker and offer the “fix”.

I think that way to merge data is pretty “new” and there projects still using the jacocoMerge ant task to do that in another way I guess.

As a quick update, in https://stackoverflow.com/a/67795882/3469592 also the following alternative approach was suggested: Use

additionalClassDirs(configurations.runtimeClasspath.filter{it.path.contains(rootProject.name)  })

instead of

additionalClassDirs(configurations.runtimeClasspath)

This also seems to work. I put a fully working example here GitHub - SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage at feature/Alternative-Approach-from-Stackoverflow-Answer