Apply plugin: 'java' fails with "org.gradle.invocation.DefaultGradle_Decorated cannot be cast to org.gradle.api.internal.project.ProjectInternal"

I have a minimal build script named tools.gradle:

apply plugin: 'java'

When I specify tools.gradle as an initialization script, with ./gradlew -I tools.gradle build, I get the following error:

FAILURE: Build failed with an exception.

* Where:
Initialization script '/Users/ping/w/remit-android/tools.gradle' line: 1

* What went wrong:
A problem occurred evaluating initialization script.
> Failed to apply plugin [id 'org.gradle.java']
   > org.gradle.invocation.DefaultGradle_Decorated cannot be cast to org.gradle.api.internal.project.ProjectInternal

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

When I specify tools.gradle as a build script, with ./gradlew -b tools.gradle build, it works fine.

I am posting mostly because I wasted a lot of time on this, and I hope no one else has to. The error message “org.gradle.invocation.DefaultGradle_Decorated cannot be cast to org.gradle.api.internal.project.ProjectInternal” is mysterious and I didn’t find any other mentions of it online; I spent several hours trying to figure out what it meant today, to no avail.

Why does the plugin work in a build script but not an initialization script? Can the error message be improved to be more helpful?

Thanks!

Build scripts and init scripts are two different things that have similar, but different APIs. The DSL guide lists the delegate objects of each under “Some basics”

A build script is backed by a Project instance. So plugins you apply in a build script will be passed the Project instance and you can call methods on the Project interface.

An init script is backed by a Gradle instance. So plugins you apply in an init script will be passed the Gradle instance and you can call methods on the Gradle interface.

In your case, you probably want to apply the plugin to each of the projects instead of the Gradle instance, so you would do something like…

allprojects {
   apply plugin: 'org.gradle.java'
}

The error should be better. I raised GRADLE-3447.

Thanks! That’s helpful.

If methods are being called on the wrong object, shouldn’t there just be an error that says there’s no such method? Or if you can apply things but you can’t apply plugins, why doesn’t the error say that apply doesn’t take a plugin argument?

Both Gradle and Project have an apply method that allows you to specify a plugin by name, so internally there’s a bit of generic plugin applying code (pseudo):

Plugin<?> plugin = findPluginByName(pluginName)
plugin.apply(delegate)

If the plugin implements Plugin<Project> and the delegate is a Gradle, you get the weird class cast exception. When I was looking into how hard it would be to add a quick check, I came across this TODO: https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/api/internal/plugins/ImperativeOnlyPluginApplicator.java#L33