Custom Gradle Plugin configuration resolution time

Hello,

I’m working on building a custom gradle plugin that cobbles a bunch of my favorite other plugins together for a micro service framework I own. Right now I’m trying to customize the ApplicationPlugin with a customStartScript.

In the service using my plugin I have something that looks like this:

plugins {
     id "com.plugin"
}

service {
    mainClass = "com.thing.MainClass"
}

In my custom plugin I have code that looks like this:

project.getTasks().register(CUSTOM_START_SCRIPT_TASK_NAME, CreateStartScripts.class, (task)->{
       ServiceConfiguration service = (ServiceConfiguration) project.getExtensions().getByName("service");
       task.setMainClassName(service.mainClass);
}

The issue is that service.mainClass is null when I debug. I’m assuming that if I could set the mainclass on the JavaApplicationPlugin convention that might do the work for me, but I can’t work out how wire up the providers to do that.

Any advice here would be greatly appreciated.

Assuming service.mainClass is a Property<String>, then your plugin can establish a default value by linking the application.mainClass and service.mainClass properties using:

YourServiceExtension sE = project.getExtensions().create("service", YourServiceExtension.class);
project.getExtensions().getByType(JavaApplication.class)
                                         .getMainClass().convention(sE.getMainClass());
1 Like

This is definitely the type of direction I was looking for. My ServiceConfiguration is a bean, I’m not really sure how to wire up the Property correctly.

I have something like this:

import org.gradle.api.provider.Property;
public class ServiceConfiguration {
       public Property<String> mainClass;
}

But when I try to register the extension the value is null.

class ServicePlugin implements Plugin<Project> { 
     @Override
     public void apply(Project project) {
           ServiceConfiguration serviceConfiguration = project.getExtensions().create("service", ServiceConfiguration.class);
           project.getExtensions().getByType(JavaApplication.class).getMainClass().convention(serviceConfiguration.mainClass);
     }    
}

I’m clearly missing a step here. This is how I’m registering the plugin.

plugins {
    `kotlin-dsl`
    `java-gradle-plugin`
}
gradlePlugin {
    plugins {
        create("service") {
            id = "com.plugin"
            implementationClass = "com.plugin.ServicePlugin"
        }
    }
}

I’ve seen examples of creating the properties for custom tasks, but that’s not really what I’m trying to do here, so I’m not totally sure what to do.

Your plugin is not creating an instance of Property<String> and assigning it to mainClass. There’s a few ways you could do this, but my recommendation is that you take advantage of Gradle’s “managed properties”. To do this change your ServiceConfiguration class to:

public abstract class ServiceConfiguration {
    public abstract Property<String> getMainClass();
}

When you then use this type for creating your extension, Gradle will generate a concrete class with the necessary implementation. You then pass convention the result of getMainClass(). Note, you do not need a setter, the property should be “final” and builds will change the value stored in the property instance, not change the property reference in the extension.

See also, Developing Custom Gradle Types

This is super awesome. Thank you so much for your help!!!