Cross-module JaCoCo Gradle coverage works for Android modules, but not for Java/Kotlin ones

Observed with both SonarQube LTS 8.9.2 and 9.2.4 (Developer edition).

Reproduced with a minimum reproducible example of a Java/Kotlin module pair (“kotlin-source” and “kotlin-test”), and another Android module pair (“android-source” and “android-test”). The “kotlin-test” module contains a test that should result in 100% coverage of “kotlin-source”, same applies for “android-test” and “android-source” respectively.

JaCoCo report is successfully merged and provided through “sonar.coverage.jacoco.xmlReportPaths”. Upon inspection of the JaCoCo report, I can see that there is a 100% coverage of both “android-source” and “kotlin-source”. However, Sonar shows “android-source” as 100% covered and “kotlin-source” as 0% covered.

Another detail is that I’ve added another test to “android-test” which tests another method in “kotlin-source”. This method in “kotlin-source” is also shown as 100% in JaCoCo report and 0% in Sonar.

I have attached the merged XML report from this example which was analyzed by Sonar. (file name changed to .txt since I wasn’t able to upload an XML file) I also attached a screenshot of the coverage report on Sonar.
jacocoJunitTestReport.txt (5.0 KB)

We found a temporary workaround for this issue by declaring xmlReportPaths differently in the root build.gradle. So instead of this:

sonarqube {
    properties {
        property("sonar.projectKey", "Coverage-sample")
        property("sonar.host.url", remote.url)
        property("sonar.coverage.jacoco.xmlReportPaths", "$buildDir/reports/jacocoJunitTestReport.xml")
    }
}

We now have this:

sonarqube {
    properties {
        property("sonar.projectKey", "Coverage-sample")
        property("sonar.host.url", remote.url)
    }
}
subprojects {
    sonarqube {
        properties {
            property("sonar.coverage.jacoco.xmlReportPaths", "${rootProject.buildDir}/reports/jacocoJunitTestReport.xml")
        }
    }
}

But I’m a bit puzzled as to why does the report path for each subproject (module) has to be defined as the merged one. Furthermore, it doesn’t explain the difference in behavior between Android and Java/Kotlin modules.