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

Object Partners profile.
Leave a Reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]