Gabor Torok
11/20/2025, 4:30 PMruntimeClasspath works, i found something weird. we are on 8.11.1 , and running this task on different projects yield weird results:
tasks.register('printMyTestClasspath') {
dependsOn 'testClasses'
doLast {
def classpathUrls = sourceSets.test.runtimeClasspath.files
classpathUrls.each {
if (!it.toString().contains(".gradle")) { // to exclude external dependencies
println "classpath file: $it"
}
}
}
}
we have a setup where we have multiple builds depending on each other via includeBuild .
what's weird is that using the above task in show inconsistent results:
• sometime the main class directory is in there (build/classes/java/main) and sometime the jar file is in there ( build/libs/something-1.0.jar )
• similarly, this is the same for the included builds - i sometimes see the classes/java/main of the dependency project, and sometimes i see the jar
• on repeated executions the results seem to stay the same.
My questions are:
• What could cause this? The build.gradle files are very similar in our different builds, i did not find any indication of what could cause this difference (sure, i could be missing something.)
• Is this a bug? Or something that has been fixed in later versions?
• Are there any workarounds that I can use to get some consistency? I want to write tooling that loads the test classes with the class loader, and then checks stuff on them - but i am getting random errors, based on weather some projects classpath has the jar or the classes ...Chris Lee
11/20/2025, 4:47 PMGabor Torok
11/20/2025, 4:59 PMjar artifact is there on the runtimeClasspath , instead of the classes - even when the jar does not exist, which is causing errors...Chris Lee
11/20/2025, 5:00 PMGabor Torok
11/20/2025, 5:09 PMdependsOn "assemble" kinda works for runtime dependencies, but it still does not build test runtime dependencies (like test fixtures).
also - when and where does gradle decide to use the jar even if it does not exist yet? if it does not exist yet - how to trigger it's build?
and i see cases where an included project has both it's classes dir and it's jar on the classpath...Vampire
11/20/2025, 5:29 PMjava-library plugin, it gets additional secondary variants that expose for example the classes directory.
Compilation tasks request the classes directory and compatibility rules allow to get the jar if no variant for the classes directory exist, so that if you depend on a project that does not apply the java-library plugin for example, you can still get the jar.Vampire
11/20/2025, 5:30 PMVampire
11/20/2025, 5:31 PMVampire
11/20/2025, 5:33 PMtestClasses are built, which might of course miss things in the runtime classpath and on the ohter hand might build things without reasonVampire
11/20/2025, 5:33 PMdependsOn is evil (unless a lifecycle task is on the left-hand side)Gabor Torok
11/20/2025, 5:34 PMtasks.register('dummyTest', Test) {
exclude "**"
}
tasks.register('verifyTestClassPath') {
dependsOn 'dummyTest'
doLast {
def classpathUrls = sourceSets.test.runtimeClasspath.files
classpathUrls.each {
if (!it.toString().contains(".gradle")) { // to exclude external dependencies
if (it.name.endsWith('.jar') && !it.exists()) {
throw new GradleException("Classpath file does not exist: $it")
}
}
}
}
}
if i clean every project and run verifyTestClassPath when it depends on testClasses - it will fail.
if i do the same but depend on the dummyTest - it won't fail.
still yucky... 😛Gabor Torok
11/20/2025, 5:36 PMVampire
11/20/2025, 5:38 PMTest task cause anything to build?
It does not do anything and does not have any inputs.Vampire
11/20/2025, 5:38 PMdependsOn and just doing inputs.files(configurations.testRuntimeClasspath)Gabor Torok
11/20/2025, 5:49 PMThat should not do anything.
Why should yourtask cause anything to build?Test
It does not do anything and does not have any inputs.yet it still works for some reason :)
Gabor Torok
11/20/2025, 5:50 PMBesides that, probably just removing the evilokay, that seems to work too! and simpler! and makes more sense! thank you! 🙂and just doingdependsOninputs.files(configurations.testRuntimeClasspath)