stemkev
(kevin.stembridge.dev)
October 18, 2025, 9:47am
1
I’m writing a plugin that has a task that must be configured with custom dependencies. I’m following the example in the documentation…
This is roughly what my Plugin and Extension look like so far…
package org.something.gen.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
abstract class GenPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create("gen", GenExtension::class.java)
extension.kotlinOutputDir.convention(project.layout.projectDirectory.dir("src/generated/kotlin/main"))
project.configurations.dependencyScope("genImplementation") {
fromDependencyCollector(extension.dependencies.getImplementation())
}
project.tasks.register("generateModel", GenerateModelTask::class.java) {
specificationClassNames.set(extension.specificationClassNames)
srcMainKotlinDir.set(extension.kotlinOutputDir)
}
}
}
package org.somethig.gen.plugin
import org.gradle.api.Action
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.Nested
import javax.inject.Inject
abstract class GenExtension @Inject constructor(objects: ObjectFactory) {
val specificationClassNames = objects.listProperty(String::class.java)
val kotlinOutputDir = objects.directoryProperty()
@Nested
val dependencies: MaiaGenDependencies = objects.newInstance(MaiaGenDependencies::class.java)
fun dependencies(action: Action<MaiaGenDependencies>) {
action.execute(dependencies)
}
}
But when I run the task, I get a ClassNotFoundException when trying to access one of the classes that are defined in the custom dependency.
I think the dependencies are probably being added to the custom Configuration correctly. What I don’t understand is how do I make that Configuration available on the classpath of the Task at runtime?
Vampire
(Björn Kautler)
October 18, 2025, 9:58am
2
You shared many information but left out the most important ones. What does that task do and which exception do you get exactly?
stemkev
(kevin.stembridge.dev)
October 18, 2025, 10:16am
3
Thanks for the quick response.
This is a simplified version of the Task.
package org.something.gen.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import org.something.gen.generator.ModelDefInstantiator
import org.something.gen.spec.definition.ModelDef
abstract class GenerateModelTask : DefaultTask() {
@get:Input
abstract val specificationClassNames: ListProperty<String>
@get:InputFiles
@get:Optional
abstract val srcMainKotlinDir: DirectoryProperty
@TaskAction
fun generateModel() {
val modelDefs = specificationClassNames.get().map { ModelDefInstantiator.instantiate(it) }
}
}
And this is what the ModelDefInstantiator does…
package org.somethig.gen.generator
import org.something.gen.spec.definition.ModelDef
import org.something.gen.spec.definition.ModelDefProvider
object ModelDefInstantiator {
fun instantiate(specClassname: String): ModelDef {
val clazz = Class.forName(specClassname)
val constructor = clazz.constructors[0]
val provider = constructor.newInstance() as ModelDefProvider
return provider.modelDef
}
}
And in my build script I have this…
gen {
specificationClassNames = listOf("some.package.Spec")
dependencies {
getImplementation().add(project(":some:module:spec"))
}
}
When the task runs, I get a ClassNotFoundException from the call to Class.forName(…)
Vampire
(Björn Kautler)
October 18, 2025, 9:23pm
4
Yeah, of course.
Why should the class magically appear on the build script class loader from which you try to load it?
You probably need to either work with a custom classloader or use the worker API with classloader or process isolation.
stemkev
(kevin.stembridge.dev)
October 19, 2025, 9:01am
5
Thanks for the suggestion.
I managed to get it working by using the Worker API.
1 Like