How to add build/classes/main to classpath of custom plugin

I have a custom plugin that needs to be able to load a class that has been compiled into build/classes/main in a previous step. The class is compiled ok and exists in the correct output directory but I get a ClassNotFoundException when the plugin tries to load it.

I’m guessing that output directory is not on the plugin’s classpath. How can I add it? Or is there some location that I can compile the class to so that it will automatically be visible to the plugin?

I don’t understand your problem description. Which ‘build/classes/main’? What previous step? Does the plugin live in ‘buildSrc’?

Hi Peter, The build/classes/main directory is the same one that is used as the standard output directory of a project that has the scala plugin applied. This project also has my plugin applied to it.

My plugin adds a SourceSet (src/modelgen/scala) and configures it to have the same output directory as the ‘main’ source set (build/classes/main). The plugin also adds a GenerateModelTask and sets up task dependencies so that compileScala dependsOn generateModel, which depends on compileModelgenScala.

So in the first step, the model descriptor classes in src/modelgen/scala are compiled into build/classes/main.

In the second step, the generateModel task reads the compiled model descriptor and generates source code in build/generated-src/scala/main (which is added as a srcDir to the main scala source set). In the third step, all of the scala source code in src/main/scala and build/generated-src/scala/main are compiled into build/classes/main.

The problem I’m having is that the generateModel task in step 2 cannot see the compiled model descriptor classes that have been compiled into build/classes/main in step 1.

The plugin does not live in buildSrc. I’m packaging it and adding it as a dependency in the buildScript block.

This is the source of the plugin:

class ModelGenPlugin implements Plugin<Project> {
                @Override
    public void apply(Project project) {
          project.apply plugin: 'scala'
                  project.extensions.create("modelgen", ModelGenExtension, project)
          project.sourceSets {
            main {
                scala {
                    srcDir 'build/generated-src/scala/main'
                }
            }
            modelgen {
                compileClasspath = project.sourceSets.main.compileClasspath
                output.classesDir = project.sourceSets.main.output.classesDir
            }
        }
          def generateModelTask = project.tasks.create("generateModel", ModelGenTask)
          generateModelTask.dependsOn project.tasks[project.sourceSets.modelgen.getCompileTaskName('scala')]
          project.compileJava.dependsOn generateModelTask
      }
    }

This is the task:

class ModelGenTask extends DefaultTask {
            @TaskAction
    def generateModel() {
          def modelgenSrcDir = project.file(project.modelgen.modelDescriptorsSrcDir)
        def generatedScalaSourcesDir = project.file(project.modelgen.generatedSrcDir)
        def modelDescriptorClassName = project.modelgen.modelDescriptorClass
          if (modelgenSrcDir.exists() == false) {
            throw new InvalidUserDataException("The supplied model descriptor source directory does not exist: ${modelgenSrcDir}")
        }
          if (modelDescriptorClassName == null) {
            throw new InvalidUserDataException("Please specify the name of your model descriptor class under the property 'modelgen.modelDescriptorClass'.")
        }
          def modelGenerator = new ModelGenerator(modelDescriptorClassName, generatedScalaSourcesDir, logger);
        modelGenerator.generateModel();
              }
            }

If your plugin needs to execute classes generated by the build, it can either run them as an external process (e.g. with a ‘JavaExec’ task), or it can create its own class loader, load the classes from there, and run them reflectively.