A comprehensive guide to Custom Application Command in Grails framework

Puneet Behl
5 min readMay 29, 2024

--

With the release of Grails 6, developers are greeted with a revamped Command-line Interface (CLI) that promises improved speed and flexibility over its predecessor. One of the standout features of this new CLI is the elimination of redundant tasks like ‘grails run-app’, streamlining the development process significantly.

Limitations of the New CLI Environment

While the revamped CLI offers enhanced performance, it operates entirely offline, lacking awareness of the Grails application or its plugins. This change disrupts the traditional approach to executing custom scripts within the Grails environment. Previously, developers could create custom scripts to automate tasks or extend functionality. However, with the CLI’s new offline mode, the concept of custom scripts becomes obsolete.

The Demise of Custom Scripts: What No Longer Works

Consider the following example of the create-script command written in Groovy from functionalities that are affected by the transition to the new CLI environment:

description( "Creates a Grails script" ) {
usage "grails create-script <<SCRIPT NAME>>"
argument name:'Script Name', description:"The name of the script to create"
flag name:'force', description:"Whether to overwrite existing files"
}

def scriptName = args[0]
def model = model(scriptName)
def overwrite = flag('force') ? true : false

render template: template('artifacts/Script.groovy'),
destination: file("src/main/scripts/${model.lowerCaseName}.groovy"),
model: model,
overwrite: overwrite

The Need for Custom Application Commands

Despite this limitation, developers can still extend the functionality of their Grails applications through custom application commands implemented via plugins. This approach ensures that even in the new offline CLI environment, developers can efficiently enhance their Grails projects.

Implementing Custom Commands: A Practical Example

To demonstrate how you can implement a custom application command within a Grails plugin, let’s walk through creating a custom command named ‘custom-command’.

Step-by-Step Implementation

  1. Define the Custom Command: Create a new Groovy file for your command in your plugin’s directory:
// grails-app/commands/your/plugin/package/CustomCommand.groovy

package your.plugin.package

import grails.cli.GrailsApplicationCommand
import org.springframework.beans.factory.annotation.Autowired

class CustomCommand implements GrailsApplicationCommand {

static final USAGE = "Usage: ./gradlew runCommand -Pargs=\"custom-command\""

static final COMMAND_NAME = 'custom-command'

@Autowired
YourService yourService // Assuming you have a service you want to use

@Override
String getName() {
COMMAND_NAME
}

@Override
String getDescription() {
"This is a custom command example."
}

@Override
String getUsage() {
USAGE
}

@Override
boolean handle() {
// Add your custom logic here
yourService.doSomething()
println "Executing custom command..."
return true // Return true to indicate successful execution
}
}

2. Run the Custom Command: Once you have defined your custom command, you can run it using Gradle:

./gradlew runCommand -Pargs="custom-command"

Adding the Plugin Dependency

To make sure your custom command is recognized and can be executed, you need to add your plugin as a dependency in your build.gradle file within the buildSrc directory:

// buildSrc/build.gradle

repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.grails.org/grails/core/" }
}

dependencies {
implementation("com.bertramlabs.plugins:asset-pipeline-gradle:4.3.0")
implementation("org.grails:grails-gradle-plugin:6.2.1-SNAPSHOT")
implementation("org.grails.plugins:hibernate5:8.1.0")
implementation("your.plugin.package:myplugin:1.0.0") { transitive = false }
}

This setup will create a Gradle task named customCommand, which you can execute with:

./gradlew customCommand -Pargs="option1 option2 ..."

Real-world Example: Grails Spring Security Core Plugin

The Grails Spring Security Core Plugin provides a practical example of how to implement and use a custom application command. The s2-quickstart command is a popular feature of this plugin and can be executed in the new CLI environment using:

./gradlew runCommand -Pargs="s2-quickstart"

Integrating Custom Commands with Grails Forge CLI

Looking towards the future, there’s an exciting prospect of integrating plugins as features into the upcoming Grails Forge CLI. This addition would allow developers to seamlessly include custom commands within the Grails CLI environment, ensuring accessibility and ease of use.

For instance, take a look at this example command implementation:

package org.grails.forge.cli.command;

import picocli.CommandLine;

@CommandLine.Command(name = "custom-command", description = "A custom command example")
public class CustomCommand implements Runnable {

@Override
public void run() {
System.out.println("Executing custom command...");
// Add your custom logic here
}
}

In this example, the CustomCommand class represents a custom command named "custom-command". By annotating the class with @CommandLine.Command, it becomes recognizable to the Grails Forge CLI. Within the run() method, developers can implement custom logic to be executed when the command is invoked.

Is there an option in the command “not-to-start” the application?

In Grails, GrailsApplicationCommand is used to create commands that can be run from the command line. By default, when running a command, Grails starts the entire application context, which can be time-consuming and resource-intensive, especially for simple tasks that don't require the full application context.

However, there are scenarios where you might want to create a command that doesn’t start the entire application. Unfortunately, as of Grails 6(the latest major version), there’s no built-in way to run a command without starting the application. Grails commands are designed to be executed within the context of a running Grails application.

That said, there are a few alternative approaches you can consider:

1. Create a Groovy Script: Use a simple Groovy script for tasks that don’t need the full Grails application context. Groovy scripts can be run directly from the command line and are much faster for lightweight tasks. Example:

// Example script: scripts/MyScript.groovy
println "This is a standalone Groovy script."
  • Run the script using:
groovy scripts/MyScript.groovy

2. Use Grails Console: The Grails console can be used for quick tasks without starting the entire application. Example:

grails console
  • In the console, you can execute Groovy code that interacts with your application without fully starting it.

3. Custom Bootstrapping: If you need some parts of the application but not. the entire context, you can customize the bootstrapping process. This is more advanced and involves modifying how the Grails application is initialized.

4. Command Line Applications: For complex tasks that don’t need Grails’ full functionality, consider creating a standalone command-line application using Java or Groovy. This can be packaged and run independently of Grails.

While Grails is powerful, it does have its limitations in terms of lightweight command execution. For simple tasks, using Groovy scripts or the Grails console is often the most efficient approach. For more complex needs, separating the functionality into a dedicated application might be the best route.

Conclusion

Grails 6 introduces a more efficient CLI, but it comes with the trade-off of reduced plugin command functionality. By leveraging Gradle tasks, you can still create powerful custom commands that integrate seamlessly with your Grails application. This approach ensures that you retain the extensibility and power of Grails while benefiting from the improved performance of the new CLI.

By embracing custom commands, developers can tailor their Grails projects to their specific needs, enhancing productivity and efficiency in their development workflows. As the Grails ecosystem evolves, the integration of custom commands promises to further enrich the development experience, cementing Grails as a versatile and developer-friendly framework.

--

--

Puneet Behl

Grails Product Development Lead | Principal Engineer | Grails framework, Apache Groovy, Spring, Spring Boot, Web Development, Gradle, Develocity