Hi, What’s the best way to publish a Gradle pre-co...
# kotlin-dsl
s
Hi, What’s the best way to publish a Gradle pre-compiled script plugins to Maven Central that uses a version catalog? Let me explain the project structure in more detail. • I have a plugin project that contains many Gradle pre-compiled script plugins. The plugin uses Gradle version catalog entries for adding dependencies or applying plugins. Currently, I’m using a hack to expose the version catalog in pre-compiled script plugins (
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
). Everything is building fine, and I can publish the plugin JAR artifact to Maven Central (I’m not using Gradle plugin marker artifacts). • Now, I want to consume the plugin in another project. The project will use a settings plugin (from the published plugin project) and the same version catalog file. Here’s the first issue I’m encountering:
Copy code
> Could not create an instance of type org.gradle.accessors.dm.LibrariesForLibs.
> Could not generate a decorated class for type LibrariesForLibs.
> org/gradle/api/internal/attributes/ImmutableAttributesFactory
I could fix this by adding the generated catalog version classes to the plugin jar artifact. However, this introduces a new issue: when the plugin is used in the consumer project, it conflicts with the version catalog classes generated there. Additionally, new entries added to the consumer’s version catalog are not showing up. Is there any suggestion or tip on how to properly use a version catalog in this scenario, or am I complicating things here? Thanks!
v
Adding the generated class to your plugin is a very bad idea.. What is the full
--stacktrace
or build
--scan
URL of the error?
s
Copy code
* Exception is:
org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'native-image-playground'.
        at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:84)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:77)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.access$500(LifecycleProjectEvaluator.java:55)
        at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyBeforeEvaluate.run(LifecycleProjectEvaluator.java:195)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
.....

Caused by: org.gradle.api.reflect.ObjectInstantiationException: Could not create an instance of type org.gradle.accessors.dm.LibrariesForLibs.
        at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.doCreate(DependencyInjectingInstantiator.java:67)
        at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.newInstanceWithDisplayName(DependencyInjectingInstantiator.java:48)
        at org.gradle.internal.extensibility.DefaultConvention.instantiate(DefaultConvention.java:229)
        at org.gradle.internal.extensibility.DefaultConvention.create(DefaultConvention.java:138)
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors.createExtensions(DefaultDependenciesAccessors.java:259)
        at org.gradle.api.internal.project.ProjectFactory.lambda$createProject$0(ProjectFactory.java:69)
        at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:99)
        at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:87)
.....

       at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)
Caused by: org.gradle.internal.instantiation.ClassGenerationException: Could not generate a decorated class for type LibrariesForLibs.
        at org.gradle.internal.instantiation.generator.AbstractClassGenerator.generateUnderLock(AbstractClassGenerator.java:260)
        at org.gradle.cache.internal.DefaultCrossBuildInMemoryCacheFactory$AbstractCrossBuildInMemoryCache.get(DefaultCrossBuildInMemoryCacheFactory.java:130)
        at org.gradle.internal.instantiation.generator.AbstractClassGenerator.generate(AbstractClassGenerator.java:190)
        at org.gradle.internal.instantiation.generator.AsmBackedClassGenerator.generate(AsmBackedClassGenerator.java:123)
        at org.gradle.internal.instantiation.generator.ParamsMatchingConstructorSelector.forParams(ParamsMatchingConstructorSelector.java:44)
        at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.doCreate(DependencyInjectingInstantiator.java:59)
        ... 186 more
Caused by: java.lang.NoClassDefFoundError: org/gradle/api/internal/attributes/ImmutableAttributesFactory
        at org.gradle.internal.instantiation.generator.AbstractClassGenerator.generateUnderLock(AbstractClassGenerator.java:247)
        ... 191 more
Caused by: java.lang.ClassNotFoundException: org.gradle.api.internal.attributes.ImmutableAttributesFactory
        at org.gradle.internal.classloader.VisitableURLClassLoader$InstrumentingVisitableURLClassLoader.findClass(VisitableURLClassLoader.java:186)
        ... 192 more
The stacktrace is so big, so I had to trim some unwanted (according to me 🙂 ) traces . I know adding generated class is a bad idea, unfortunately haven’t find any other workaround.
p
I generally use a task that writes the dependency notation as a string to a source code file and use the string in the Gradle plugin, https://github.com/hfhbd/mavencentral/blob/main/gradle-plugin/build.gradle.kts#L25
s
@Philip W thanks very much..will check it.
v
Do you include the
LibrariesForLibs
in your plugin artifact? Because you should not. It is a generated class and if you include that in your plugin, it could very easily be that it is not compatible. I'd say in your case you built the plugin with Gradle 8.11 or earlier and included the generated
LibrariesForLibs
class which then somehow uses the internal
ImmutableAttributesFactory
class. This class was renamed to
AttributesFactory
in 8.12 and the old one is not found anymore. So when you now apply the plugin to a Gradle 8.12 build, it fails with the exception you showed. Do not include the generated
ImmutableAttributesFactory
class and all should work as epected, or consider stopping to using my hack-around and instead use the string-y way to access the version catalog entries. The suggestion by @Philip W can of course also work, but only if you do not want the consumer to be able to control the versions, which seems to be the sense of it. Otherwise it would not make sense to read from the version catalog at runtime in the first place and generating the info into a resource file you use at runtime would of course be the better solution.
s
should work as epected,
I am getting the error only when the generated classes are not included. Using the same latest gradle version for both plugin and consumer projects
Copy code
Caused by: java.lang.TypeNotPresentException: Type org.gradle.accessors.dm.LibrariesForLibs not present
        at org.gradle.api.reflect.TypeOf.captureTypeArgument(TypeOf.java:299)
        at org.gradle.api.reflect.TypeOf.<init>(TypeOf.java:96)
        at common.ProjectExtnsKt$special$$inlined$the$1.<init>(TypeOfExtensions.kt:28)
        at common.ProjectExtnsKt.getLibs(ProjectExtns.kt:744)
        at common.ProjectExtnsKt.getGithubUser(ProjectExtns.kt:107)
        at common.ProjectExtnsKt.getGithubRepo(ProjectExtns.kt:110)
        at Dev_suresh_plugin_kotlin_docs_gradle$2$2.execute(dev.suresh.plugin.kotlin.docs.gradle.kts:75)
        at Dev_suresh_plugin_kotlin_docs_gradle$2$2.execute(dev.suresh.plugin.kotlin.docs.gradle.kts:73)
        at org.gradle.internal.extensibility.ExtensionsStorage$ExtensionHolder.configure(ExtensionsStorage.java:177)
        at org.gradle.internal.extensibility.ExtensionsStorage.configureExtension(ExtensionsStorage.java:64)
        at org.gradle.internal.extensibility.DefaultConvention.configure(DefaultConvention.java:207)
        at gradle.kotlin.dsl.accessors._f9650e3495f1d41c8ec360d28cd41cbc.Accessors90yi2h033leqh9fwa89xpqu5xKt.html(Accessors90yi2h033leqh9fwa89xpqu5x.kt:73)
        at Dev_suresh_plugin_kotlin_docs_gradle$2.execute(dev.suresh.plugin.kotlin.docs.gradle.kts:73)
        at Dev_suresh_plugin_kotlin_docs_gradle$2.execute(dev.suresh.plugin.kotlin.docs.gradle.kts:34)
        at org.gradle.internal.extensibility.ExtensionsStorage$ExtensionHolder.configure(ExtensionsStorage.java:177)
        at org.gradle.internal.extensibility.ExtensionsStorage.configureExtension(ExtensionsStorage.java:64)
        at org.gradle.internal.extensibility.DefaultConvention.configure(DefaultConvention.java:207)
        at gradle.kotlin.dsl.accessors._f9650e3495f1d41c8ec360d28cd41cbc.Accessorsadhq1lcpj9r3vuwun5mgy740sKt.dokka(Accessorsadhq1lcpj9r3vuwun5mgy740s.kt:73)
        at Dev_suresh_plugin_kotlin_docs_gradle.<init>(dev.suresh.plugin.kotlin.docs.gradle.kts:34)
        at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
        at Dev_suresh_plugin_kotlin_docsPlugin.apply(Dev_suresh_plugin_kotlin_docsPlugin.kt:13)
        at Dev_suresh_plugin_kotlin_docsPlugin.apply(Dev_suresh_plugin_kotlin_docsPlugin.kt:6)
        at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:54)
        at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:190)
        at org.gradle.api.internal.plugins.DefaultPluginManager.access$100(DefaultPluginManager.java:54)
        at org.gradle.api.internal.plugins.DefaultPluginManager$AddPluginBuildOperation.run(DefaultPluginManager.java:285)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.api.internal.plugins.DefaultPluginManager.lambda$doApply$0(DefaultPluginManager.java:170)
        at org.gradle.internal.code.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:169)
        ... 216 more
Caused by: java.lang.ClassNotFoundException: org.gradle.accessors.dm.LibrariesForLibs
        at org.gradle.internal.classloader.VisitableURLClassLoader$InstrumentingVisitableURLClassLoader.findClass(VisitableURLClassLoader.java:186)
        ... 253 more
on the consumer project side, i am applying a settings plugins inside the
plugins{}
in
settings.gradle.kts
(if that matters)
Is this because the
LibrariesForLibs
are generated after loading the settings plugins ?
p
Well, the „workaround“ I use is the default gradle handling. A user can always overwrite the version by using a version constraint or pass a higher gav to the configuration. Does the generated class also work, if a user does not name the catalog
libs
?
s
Does the generated class also works, if a user does not name the catalog
libs
?
I tried that (created buildlibs)…same error if don’t include the generated classes.
Copy code
Caused by: java.lang.ClassNotFoundException: org.gradle.accessors.dm.LibrariesForBbuildlibs
        at org.gradle.internal.classloader.VisitableURLClassLoader$InstrumentingVisitableURLClassLoader.findClass(VisitableURLClassLoader.java:186)
        ... 253 more
v
I am getting the error only when the generated classes are not included. Using the same latest gradle version for both plugin and consumer projects
Nah, that's a different error than you showed before. If you would have shown that, then the settings plugin would have been my answer.
on the consumer project side, i am applying a settings plugins inside the plugins{} in settings.gradle.kts (if that matters)
Most probably, yes. The design is, that a settings plugin can contribute a version catalog. So the accessors are not available in the settings script, but only after the settings were executed. That also means that the generated class for the version catalog is only available in a child class loaders of the settings class loader, so even during project plugin application - as the classes are coming from the settings class loader - they will not be able to see the generated class. Options you have include: • split the plugins into two artifacts / projects, one for settings plugins, one for project plugins, that way the project plugins do not land on the settings class loader but will see the generated class • do not use the generated accessors, but the string-y access through the version catalogs extension • generate the versions / entries to some resource file that you then read at execution time
A user can always overwrite the version by using a version constraint or pass a higher gav to the configuration.
Sure, but that is cumbersome if it is explicitly intended for the user to modify that version if they also want to preserve the advantages of version catalogs.
Does the generated class also work, if a user does not name the catalog libs?
No, the
Libs
in the class name is the catalog name. Just like it wouldn't work if the expected entries are not present in the catalog.
s
@Vampire thanks very much for the detailed explanation.
• split the plugins into two artifacts / projects, one for settings plugins, one for project plugins, that way the project plugins do not land on the settings class loader but will see the generated class
I tried to split the project and settings plugin in two different artifacts ..settings plugin have no access to version catalog and only project use the default version catalog. Now when i apply the project plugin in my consume project build, still seeing the following error.
Copy code
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin 'dev.suresh.plugin.kotlin.docs'.
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:176)
        at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:148)
        at org.gradle.kotlin.dsl.precompile.v1.PrecompiledProjectScript$plugins$1.id(PrecompiledScriptTemplates.kt:175)
        at Dev_suresh_plugin_root_gradle$1.invoke(dev.suresh.plugin.root.gradle.kts:11)
        at Dev_suresh_plugin_root_gradle$1.invoke(dev.suresh.plugin.root.gradle.kts:7)
        at org.gradle.kotlin.dsl.precompile.v1.PrecompiledProjectScript.plugins(PrecompiledScriptTemplates.kt:172)
        at Dev_suresh_plugin_root_gradle.<init>(dev.suresh.plugin.root.gradle.kts:7)
        at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
        at Dev_suresh_plugin_rootPlugin.apply(Dev_suresh_plugin_rootPlugin.kt:13)
        at Dev_suresh_plugin_rootPlugin.apply(Dev_suresh_plugin_rootPlugin.kt:6)
        at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:54)
        at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:190)
        at org.gradle.api.internal.plugins.DefaultPluginManager.access$100(DefaultPluginManager.java:54)
        at org.gradle.api.internal.plugins.DefaultPluginManager$AddPluginBuildOperation.run(DefaultPluginManager.java:285)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.api.internal.plugins.DefaultPluginManager.lambda$doApply$0(DefaultPluginManager.java:170)
        at org.gradle.internal.code.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:169)
        at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:148)
        at org.gradle.plugin.use.resolve.internal.ArtifactRepositoriesPluginResolver$ExternalPluginResolution.applyTo(ArtifactRepositoriesPluginResolver.java:151)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator$ApplyAction.apply(DefaultPluginRequestApplicator.java:160)
        ... 188 more
Caused by: java.lang.TypeNotPresentException: Type org.gradle.accessors.dm.LibrariesForLibs not present
        at org.gradle.api.reflect.TypeOf.captureTypeArgument(TypeOf.java:299)
        at org.gradle.api.reflect.TypeOf.<init>(TypeOf.java:96)
        at common.ProjectExtnsKt$special$$inlined$the$1.<init>(TypeOfExtensions.kt:28)
v
While having the same version catalog in the target project available? I guess now would be a point you need to provide an MCVE for any meaningful help.
s
While having the same version catalog in the target project available?
yes.. i will share the project soon
👌 1
having the same version catalog in the target project available?
@Vampire You are right, everything worked after splitting the plugins into project and settings modules to avoid classloader problems (ugh..hope gradle can solve this) . The issue originated with my producer project. Now everything functions correctly without the need for generated classes and utilizing user-provided version catalog files. Thank you very much for your help and guidance, really appreciated 🙏
v
There is nothing Gradle folks could do to "solve" this, it works as designed. :-)
The class loader topic I mean. The general issue where my hack-around is found, we'll see.
👍 1