Passing Command Line Arguments to a Spring Boot Application via a bootRun Task in Gradle

There currently seems to be no easy way to pass arguments to a Spring Boot application launched using the bootRun task in Gradle. There are plenty of stack overflow questions asking about this and at least one active issue for Spring Boot: https://github.com/spring-projects/spring-boot/issues/1176.

I ran into this while working on a small utility application for a previous client. In order to support the conversion of a number of mainframe applications to web applications, they needed to add LDAP network ids to an “operator” authorization DB2 table containing mainframe user ids that was used by existing stored procedures and some of the converted applications. The utility application read in an excel export of the network users and matched up records to the mainframe users, creating an entry for the ldap id with the same authorization privileges.

While developing this utility application I became frustrated that I did not have a good way to pass in the excel workbook location and worksheet name to the application the same way when running it as either an executable jar or via a bootRun task. I did not enjoy having to rebuild the jar to test changes to the application and did not want to pass that information via system properties or to hard code those values in for development (as I did not trust myself to always remember to remove them before committing changes).

In the application I was using a SimpleCommandLinePropertySource to pull out the arguments.

static void main(String[] args) {
...
    PropertySource propertySource = new SimpleCommandLinePropertySource(args)
    log.info("propertySource.properties: ${propertySource.properties}")
 
    List commandLineArgs = propertySource.getNonOptionArgs()
    String excelFilePath = commandLineArgs?.first()
    String workSheetName = commandLineArgs?.last()
....
}

This worked fine when I built the executable jar and ran it like the following:

java -jar ./build/libs/SpringBootArgsExample.jar ./src/test/resources/testData.xlsx sheet1

But I was not able to pass the arguments when I used bootRun or any of the custom bootRun tasks I had extended to set the profile to the correct environment: dev, test, prod.

After some research, I came to the solution of creating a task execution listener that would collect any arguments from the task’s project and pass them on to the task being called as long as the task was a org.springframework.boot.gradle.run.BootRunTask.

class BootRunPropertyListener implements TaskExecutionListener {
    void afterExecute(Task t, TaskState s) {}
 
    void beforeExecute(Task t) {
        if (t instanceof org.springframework.boot.gradle.run.BootRunTask) {
            if (t.project.hasProperty('args')) {
                String arguments = t.project.properties['args']
                Collection args = arguments.split('\\s+')
                t.args = args
            }
        }
    }
}

I then added that listener to the project and created custom tasks that extended org.springframework.boot.gradle.run.BootRunTask.

project.gradle.addListener(new BootRunPropertyListener())
 
task bootRunH2(type: org.springframework.boot.gradle.run.BootRunTask) {
    doFirst() {
        main = project.mainClassName
        classpath = sourceSets.main.runtimeClasspath
        systemProperty "spring.profiles.active", "H2"
    }
}
 
task bootRunDev(type: org.springframework.boot.gradle.run.BootRunTask) {
    doFirst() {
        main = project.mainClassName
        classpath = sourceSets.main.runtimeClasspath
        systemProperty "spring.profiles.active", "Dev"
    }
}

This allowed me to run my different tasks and easily pass in the desired arguments using -Pargs:

gradlew bootRunH2 -Pargs="./src/test/resources/testData.xlsx sheet1"

I know this is only one of many ways to solve this issue, but hopefully it saves someone some time trying to figure out a way to solve it.

I have posted a small example application of the solution to github.

About the Author

Rob Boler profile.

Rob Boler

Sr. Consultant

Rob has always been interested in computers, and remembers first attempting programming a hangman game on an Apple IIE in grade school. He has over 15 years of software development experience using Java / Spring, primarily in the transportation and defense industries. He prides himself as being able to solve complex software problems, while also being able to lead small teams of developers. Rob has a wide range of project experience ranging from dynamic web applications to high volume message processing, to applying Big Data technologies for data pattern analysis.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
AWS Cloud HSM, Docker and NGINX
There is quite a bit of easily searchable content on the security benefits of leveraging a Hardware Security Module to manage cryptographic keys, so I will leave that to the scope of another article. The […]
Google Professional Machine Learning Engineer Exam 2021
Exam Description A Professional Machine Learning Engineer designs, builds, and productionizes ML models to solve business challenges using Google Cloud technologies and knowledge of proven ML models and techniques. The ML Engineer is proficient in all aspects […]
Designing Kubernetes Controllers
There has been some excellent online discussion lately around Kubernetes controllers, highlighted by an excellent Speakerdeck presentation assembled by Tim Hockin. What I’d like to do in this post is explore some of the implications […]
React Server Components
The React Team recently announced new work they are doing on React Server Components, a new way of rendering React components. The goal is to create smaller bundle sizes, speed up render time, and prevent […]