No value Has been specified for property 'classpath'

Hi,
I use the cargo plugin (2.8.0) to deploy on payara servers.
To do this, I have a gradle file (master) which contains this:

buildscript {
    repositories {
        maven {
            url = "http://w2016-nexus.fedris.be:8089/nexus/repository/maven-central/"
        }
        maven {
            url = "http://w2016-nexus.fedris.be:8089/nexus/repository/plugin-gradle/"
        }
    }
    dependencies {
        classpath("com.bmuschko:gradle-cargo-plugin:2.8.0")
    }
}

and my cargo tasks are in another gradle file (deployment.gradle - not in project)
apply from: System.getenv('GRADLE_UTILS') + '\\fedris\\deployment.gradle'

Everything works fine.

but now I want to use Sonarqube plugin. So I modified my dependencies to add this plugin.

So I have this in my buildscript

buildscript {
    repositories {
        maven {
            url = "http://w2016-nexus.fedris.be:8089/nexus/repository/maven-central/"
        }
        maven {
            url = "http://w2016-nexus.fedris.be:8089/nexus/repository/plugin-gradle/"
        }
    }
    dependencies {
        classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
        classpath("com.bmuschko:gradle-cargo-plugin:2.8.0")
    }
}

simply adding a new classpath in the dependencies causes cargo to no longer work. It gives me the following error:

A problem was found with the configuration of task ‘:undeployFromGlassfish’.

No value has been specified for property ‘classpath’.

how can i solve this problem? I imagine that it is possible to use several plugins at the same time

here is a project that reproduces the problem: GitHub - morayKevin/cargo_bug

I am currently using gradle 6.x but I have the same problem with gradle 7.x. I didn’t test with gradle 8.x

in the master branch, the cargo plugin “works”

gradle undeployFromGlassfish -Pbranch=environment/test -PuserLogin=login -PuserPassword=password

I get an error from the cargo plugin just normal:

java.lang.IllegalStateException: error submitting remote command

and displaying classpath gives this:

Cargo classpath : configuration ‘:cargo’

in the bug branch, I added the sonarqube plugin, the cargo plugin don’t works

gradle undeployFromGlassfish -Pbranch=environment/test -PuserLogin=login -PuserPassword=password

I get an error with the classpath:

No value has been specified for property ‘classpath’.

and displaying classpath gives this:

Cargo classpath : null

Some sidenotes:

  • do not use script plugins, they have various quirks and are not recommended (the things you use with apply from), better use convention plugins, for example implemented as precompiled script plugins to share build logic
  • do not use the legacy add-to-buildscript-classpath / apply plugin method to apply plugins, but use the plugins { ... } block
  • the SonarQube Gradle scanner is already at version 4.0.0.2929
  • do not use subprojects { ... } or allprojects { ... } block, but again use convention plugins for shared build logic
  • do not use compile and runtime configurations, those are deprecated since Gradle 4.7 in 2018 and in Gradle 7 they are finally removed
  • always add the four Gradle wrapper files to each and every Gradle project, this way it is always and everywhere run with the correct Gradle version you designed the build for and know runs with properly and behaves as designed, if someone opens your project with a recent IDE it will not even sync properly as you depend on using an ancient Gradle version but do not declare it
  • it would be nice if an MCVE would at least also be able to sync in the IDE. Even if Gradle 6 is used, yours does not sync as it references non-existent libraries

Regarding the actual problem.
If you would follow the sidenotes above, you would not have this problem actually.
The problem is a classloader issue and the quirks of using legacy script plugins.
Simply by adding the SonarQube plugin to the root project’s buildscript classpath, but not adding it to the deployment.gradle script classpath you are causing your problem.

The cargo plugin uses tasks.withType(AbstractCargoContainerTask) { ... } to set a convention mapping (which is a Gradle internal and should not be used by 3rd party plugins anyway).
As long as the classpaths for the root project’s build script and the legacy script plugin were identical, it used the same classloader and all worked as expected.

By adding the SonarQube plugin only to the root project’s build script classpath you now have separate class loaders for the root project and for the legacy script plugin.

When you now apply the plugin by ID, it is searched for in the root project’s class loader which is also the reason you need to add the plugin to its classpath.

But the task you register using the class name inside the script plugin uses the class loader of the script plugin which does not have the root project’s class loader as parent, so uses its own version of those classes. So now the Cargo plugin that was applied from the root project’s class loader searches for all tasks with the class AbstractCargoContainerTask from the root project’s classloader, but the tasks you registered from the legacy script plugin are of type AbstractCargoContainerTask from the legacy script plugin’s classloader. Due to that, your tasks are not found and thus their classpath property does not have the convention mapping configured.

This is one of the various quirks I mentioned above, due to which legacy script plugins should be avoided wherever possible.

  • If you would get rid of the legacy script plugins, that would resolve your issue and actually is the most recommended solution.
  • If you do not apply the plugin by ID, but by class (replacing apply plugin: 'com.bmuschko.cargo-base' by apply plugin: com.bmuschko.gradle.cargo.CargoBasePlugin) it also works as then the class from the legacy script plugin is applied and thus the withType finds your custom tasks and configures them. In that case you can even remove the cargo plugin from the root project’s build script as it is no longer necessary or used at all.
  • If you make sure that the build script classpaths are identical, currently by also adding the SonarQube Gradle plugin dependency to the classpath of the legacy script plugin, the same classloader would be used and it would also work again.

Thank you very much for this long and detailed explanation.

I now have a lot of leads to solve my problem.

Thanks a lot

1 Like