Some classes that would in the tooling-api jar in previous versions are now in the launcher jar. Yet the launcher jar is not on the classpath when using the gradleApi() as a dependency. This is causing NoClassDefFoundError exceptions. E.g. if I add gradleApi() I can not access org.gradle.launcher.GradleMain. Admittedly I’m most interested in org.gradle.tooling.internal.impl.DefaultGradleProject which is used from the tooling API.
For background, it appears that some of the new module loading in 1.12 is missing some connections. ToolingRegistratonAction.execute is being called in my IDE, which results in a NoClassDefFoundError for DefaultGradleProject. It looks like ToolingRegistrationAction (from gradle-tooling.jar) uses the class GradleProjectBuilder class that is in gradle-ide.jar, but that class uses DefaultGradleProject from the gradle-launcher.jar, which is no longer in the classpath. I believe the DefaultGradleProject class was in the tooling-api jar before and now appears to be in the launcher jar, yet the launcher jar is not in my classpath in 1.12-rc-1. Hence the JVM can’t load ToolingRegistrationAction. Seems the new module loading logic isn’t matching actual dependencies. Radim, it looks like you were specifically trying to get around this in commit 876ebfe.
That line lets the launcher run with our current testRuntime classpath, which simplifies the buildscript. In 1.12-rc-1 the root class loader is now immutable, and there doesn’t seem to be any opportunity to add our classloader before the script is processed. I can sorta get around that problem. We then run the project’s execute() and run into GRADLE-3068
Further, I need to prevent the GradleConnector from trying to acquire a distribution. For my purposes the distribution is already in the calling classloader.
The tooling api does not offer the same flexibility. I think it should provide parity with GradleLauncher before the classes are removed.
How would I add a classloader to the BuildLauncher, to achieve the same thing as ‘gradle.services.get(BuildClassLoaderRegistry).addRootClassLoader(getClass().classLoader)’
This was private API and has been removed. What’s the use case you are trying to support?
We build our own Gradle distribution extended with our own plugins. As part of the build, we run unit tests that launch individual builds using Spock framework. Hence the need to use a classloader to run with in-memory distribution vs. an outside distribution.
The ‘BuildLauncher’ is not available anymore but you can use the tooling API instead. If you need to add classes to its classpath, you might want to explore adding them as part of your init script. You can point the ‘GradleConnector’ to the distribution you want to use on your local disk.
Point is that its an embedded distribution (in developement). What we need is better test harness for plugin development since most folks have used BuildLauncher for this purpose.