By the document:
https://docs.gradle.org/current/userguide/java_gradle_plugin.html
the plugin java-gradle-plugin
adds the gradleApi()
dependency to the api
configuration.
I developed a Gradle plugin by java-gradle-plugin
:
and I provide an example to use the plugin:
However, I find if I remove the line implementation gradleApi()
from example/build.gradle, the example will run (./gradlew :example:run
) to fail with the errors
Exception in thread "main" java.lang.NoClassDefFoundError: org/gradle/tooling/GradleConnector
at com.github.MrRogerHuang.GradleProjectRunner.run(GradleProjectRunner.kt:33)
at com.github.MrRogerHuang.GradleProjectRunner.run$default(GradleProjectRunner.kt:32)
at com.github.MrRogerHuang.ExampleKt.main(Example.kt:6)
at com.github.MrRogerHuang.ExampleKt.main(Example.kt)
Caused by: java.lang.ClassNotFoundException: org.gradle.tooling.GradleConnector
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 4 more
I check build/publish-generated-resources/pom.xml
generated by ./gradlew publishPlugins
and find there is no dependencies tag related to any Gradle API. Why does java-gradle-plugin
add gradleApi()
api dependency, but not generate any dependencies tag to pom.xml?
The example project should only need to depend on org.gradle:gradle-tooling-api
, instead of gradleApi()
.
https://docs.gradle.org/current/userguide/third_party_integration.html#sec:embedding_quickstart
$toolingApiVersion
should be a version chosen by you.
Thanks. Yes, I agree only org.gradle:gradle-tooling-api
is needed. However, I think that org.gradle:gradle-tooling-api
is part of gradleApi()
and java-gradle-plugin
adds the api gradleApi()
to my plugin, thus gradleApi() would be transitively exposed to the example implementing the plugin, isn’t it? With the transitive expose, the example build.gradle could be simplified by removing the an explicitly dependency to either org.gradle:gradle-tooling-api
or gradleApi()
. But in my example run, it looks like api gradleApi()
added by java-gradle-plugin
is not transitive…
gradleAPI()
is not intended to be a published set of artifacts that you depend on in your plugin’s pom. The API is provided by Gradle at runtime of your plugin. Your plugin can be applied to projects running different versions of Gradle and that specific version’s API will be made available on the plugin’s classpath. You need to be aware about what features of the Gradle API you use in your plugin (you maintain the compatibility). If the plugin uses something added in Gradle 6 and the plugin is used in a Gradle 5 project, it will fail.
The model interfaces should not contain Gradle API classes. This maintains an abstraction between the consumer of the model and any Gradle version specific API details. My personal suggestion is that you split the model classes into their own project. This helps enforce the abstraction and prevents the model from accidentally using Gradle API classes.
In summary:
- Plugin project
- Depends on
gradleAPI()
and Model
- Model project
- Application/Consumer project
- Depends on
gradle-tooling-api
and Model.
Thanks for your information and suggestions.