Programmatically set application's global mainClassName in custom plugin

Hi

I’ve been using Gradle some weeks, and I’m now trying to create my own plugin. I have several microservices, and I want to create one plugin that import in all my microservices, so that I can share common things needed by each microservice’s build. Currently I want to do two things, and that is run the gradle application plugin’s task “installDist”, and then the task Copy (in order to create an executable of my project, then copy it to somewhere specific for later use in my CI.)

Problem:
I don’t know how, or if it’s possible, to set the application plugin’s property “mainClassName”, from my custom plugin.

My plugin’s code:
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.ApplicationPlugin;

public class GreetingPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {
        project.getExtensions().create("distConfig", DistConfig.class);
        project.getPlugins().apply(ApplicationPlugin.class);

        // How can I execute application plugin's task installDist, with mainClassName set?
    }
}

public class DistConfig {
    public String main;
}

Workaround:

I am able to set the mainClassName the following way:

apply plugin: 'com.yngvark.gridwalls.common_build_plugin'
distConfig {
    main = 'mytest.Main'
}
mainClassName = 'mytest.Main' // They did it like this in https://github.com/ratpack/example-ratpack-gradle-java-app/blob/master/build.gradle

However, I believe this is not the best design, as it makes details of the application plugin leak through to my microservices. I only want the properties of my CommonBuildPlugin to be visible to my microservices.

By the way, I have read Configuring a plugin programmatically using extension variables , and while they recommend to go with the new @Model approach, I am right now just wondering if it’s possible at all do what I’m asking above.

Unfortunately the application plugin is still using an old API that you might not have seen before, so here you go :slight_smile:

project.getConvention().getPlugin(ApplicationPluginConvention.class).setMainClassName(name)

1 Like

Thank you! It works.

I can see from the source code of ApplicationPlugin.java that the same is done there.

A new problem then appeared. Your suggestion solves how to set the mainClassName, however, how do I set the variable “name” in your example?

I want my consumers/microservices to apply my plugin in this way:

apply plugin: 'common_build_plugin'
commonConfig {
    mainClassName = 'mytest.Main'
}

However, if I do this:

@Override
public void apply(Project target) {
    target.getPluginManager().apply(ApplicationPlugin.class);

    target.getExtensions().create("commonConfig", CommonConfig.class);
    String mainClassName = target.getExtensions().getByType(CommonConfig.class).mainClassName;
    System.out.println("--> Main class name: " + mainClassName);

    // Doesn't work, because mainClassName is null
    // target.getConvention().getPlugin(ApplicationPluginConvention.class).setMainClassName(mainClassName);
}

the output is “–> Main class name: null”.

I think I understand why, but I just don’t know if it’s possible to do what I’m trying, or even if what I’m trying is the best approach.

You need to give the build script a chance to configure it before you query it. You can do that by using

project.afterEvaluate { 
  /* read main class name here and put it into the application plugin's config */ 
}

Again, it worked. Thanks a lot!