Reputation: 10843
I am trying to run a command-line Java app via Gradle as part of a quick integration test. I am porting my build scripts from Maven, where this was easily done via exec-maven-plugin
. My two big requirements are:
Please note that I am not trying to read these properties in the build script, I'm trying to read them in the Java program that the script builds and executes.
I have found two other SO posts that address Java program execution via Gradle: one with an answer that advocates using apply plugin: "application"
in the build file and gradle run
at the command line, and another with answers advocating that approach as well as using task execute(type:JavaExec)
in the build file and gradle execute
at the command line. I have tried both approaches and have not succeeded.
I have two problems:
(1) I cannot get the Java executable to read the system properties
Whether I do this:
build.gradle:
apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"
Command line:
gradle run -Dmyproperty=myvalue
Or this:
build.gradle:
task execute (type:JavaExec) {
main = "com.mycompany.MyMain"
classpath = sourceSets.main.runtimeClasspath
}
Command line:
gradle execute -Dmyproperty=myvalue
In either case, myproperty
does not make it through. The code that begins running from MyMain.main (...)
reads the myproperty
system property as null/missing.
(2) I cannot pass command line arguments
This is probably related to the first problem. In exec-maven-plugin
, for example, command line args were themselves passed in via a system property. Is that the case with Gradle, or is there another way to pass command line arguments?
How do I get these variables through? Also, is it better to use apply plugin: 'application'
or task execute (type:JavaExec)
?
Upvotes: 93
Views: 84905
Reputation: 1
I just ran into this when trying to pass properties to a Spring Boot app being run with the Spring Boot Gradle plugin. The following is written in Kotlin and will pass all properties from Gradle to the Spring Boot Application.
tasks.named<BootRun>("bootRun") {
val propertiesMap = mutableMapOf<String, Any>()
System.getProperties().forEach {
propertiesMap[it.key.toString()] = it.value
}
systemProperties = propertiesMap
}
Upvotes: 0
Reputation: 12817
Maybe I am late for the party, but has anyone tried with "set the prop before executing gradle"? I have tested and this works too, apparently.
myVar=myVal gradle test
For example, you can set the active profile like:
SPRING_PROFILES_ACTIVE=dev gradle test
These also work, apparently:(tested)
set myVar=myVal && gradle test # for windows
export myVar=myVal && gradle test # for linux and mac
Be wary that myVar
cannot be period-separated; or else only the part before the first period will be taken as key.
Upvotes: -2
Reputation: 409
I'm new to gradle so I needed this and what is working for me with gradle 4.6 seems a little easier for the command line. Instead of parsing 1 arg string you can pass an array of args, and I found a way to pass in all property with one line as well. Combined below:
apply plugin: 'java'
apply plugin: 'org.springframework.boot' <- for my project
task runApp(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'testit.TomcatApp'
// arguments to pass to the application
// args 'myarg1 -rest' <- came in as 1 string
args = ["--myarg1 with spaces even", "--myarg2"]
// and to pass in all -D system property args:
systemProperties = System.properties
}
gradle run -Dwhatever=xxx -Dmyarg2=hey
// Java reading them:
public static void main(String[] args) {
for ( int i = 0; i < args.length; i++ )
{
logger.info( "** args [" + i + "] =" + args[i] + "=" );
}
logger.info( "** -Dwhatever =" + System.getProperty("whatever") + "=" );
logger.info( "** -Dmyarg2 =" + System.getProperty("myarg2") + "=" );
[main] INFO testit.TomcatApp - ** args [0] =--myarg1 with spaces even=
[main] INFO testit.TomcatApp - ** args [1] =--myarg2=
[main] INFO testit.TomcatApp - ** -Dwhatever =xxx=
[main] INFO testit.TomcatApp - ** -Dmyarg2 =hey=
Upvotes: 3
Reputation: 10843
Figured it out. The main issue is that when Gradle forks a new Java process, it does not automatically pass the environment variable values along to the new environment. One has to explicitly pass these variables via the systemProperties
property of the task or plugin.
The other issue was understanding how to pass command-line args; these are via the args
property on the task or plugin. As with the Maven exec-maven-plugin
, they should be passed in on the command line via yet another system property, as a space-delimited list that then needs to be split()
before setting args
, which accepts List
objects. I've named the property exec.args
, which is the old Maven name.
It seems both the javaExec
and application plugin approach are valid. One might favor the application plugin approach if one wants to use some of its other features (automatically putting together a distribution, etc.)
Here are the solutions:
Command Line:
gradle execute -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"
build.gradle:
task execute (type:JavaExec) {
main = "com.myCompany.MyMain"
classpath = sourceSets.main.runtimeClasspath
/* Can pass all the properties: */
systemProperties System.getProperties()
/* Or just each by name: */
systemProperty "myvariable", System.getProperty("myvariable")
/* Need to split the space-delimited value in the exec.args */
args System.getProperty("exec.args", "").split()
}
Command Line:
gradle run -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"
build.gradle:
apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"
run {
/* Can pass all the properties: */
systemProperties System.getProperties()
/* Or just each by name: */
systemProperty "myvariable", System.getProperty("myvariable")
/* Need to split the space-delimited value in the exec.args */
args System.getProperty("exec.args", "").split()
}
Upvotes: 145
Reputation: 4795
For those who might not want to pollute your application's system properties by passing unrelated Gradle props, I recommend namespacing your arguments.
tasks.withType(JavaExec) {
System.properties.each { k,v->
if (k.startsWith("prefix.")) {
systemProperty k - "prefix.", v
}
}
}
java ... -Dprefix.my.prop=true
will pass my.prop
Upvotes: 12