Problemas al pasar las propiedades del sistema y los parámetros al ejecutar la clase Java a través de Gradle

Estoy intentando ejecutar una aplicación Java de línea de comandos a través de Gradle como parte de una prueba de integración rápida. Estoy portando mis scripts de construcción desde Maven, donde esto se hizo fácilmente a través de exec-maven-plugin . Mis dos grandes requisitos son:

  • Poder pasar propiedades del sistema al código Java ejecutable
  • Ser capaz de pasar args de línea de comandos al código Java ejecutable

Tenga en cuenta que no estoy tratando de leer estas propiedades en el script de construcción, estoy tratando de leerlas en el progtwig Java que el script crea y ejecuta.

He encontrado otras dos publicaciones SO que abordan la ejecución del progtwig Java a través de Gradle: una con una respuesta que recomienda usar el apply plugin: "application" en el archivo de comstackción y gradle run en la línea de comando , y otra con respuestas que defienden ese enfoque y utilizando la task execute(type:JavaExec) en el archivo de comstackción y gradle execute en la línea de comandos . He intentado ambos enfoques y no he tenido éxito.

Tengo dos problemas:

(1) No puedo obtener el ejecutable de Java para leer las propiedades del sistema

Si hago esto:

build.gradle :

 apply plugin: 'application' mainClassName = "com.mycompany.MyMain" 

Línea de comando :

 gradle run -Dmyproperty=myvalue 

O esto:

build.gradle :

 task execute (type:JavaExec) { main = "com.mycompany.MyMain" classpath = sourceSets.main.runtimeClasspath } 

Línea de comando :

 gradle execute -Dmyproperty=myvalue 

En cualquier caso, myproperty no lo myproperty . El código que comienza a ejecutarse desde MyMain.main (...) lee la propiedad del sistema myproperty como null / missing.

(2) No puedo pasar los argumentos de línea de comando

Esto probablemente esté relacionado con el primer problema. En exec-maven-plugin , por ejemplo, los argumentos de la línea de comando se pasaban a través de una propiedad del sistema. ¿Es ese el caso de Gradle, o hay otra forma de pasar argumentos de línea de comando?

¿Cómo puedo obtener estas variables? Además, ¿es mejor usar el apply plugin: 'application' o task execute (type:JavaExec) ?

Lo averigué. El problema principal es que cuando Gradle crea un nuevo proceso Java, no pasa automáticamente los valores de la variable de entorno al nuevo entorno. Uno debe pasar explícitamente estas variables a través de la propiedad systemProperties de la tarea o el complemento.

El otro problema era entender cómo pasar argumentos de línea de comandos; estos son a través de la propiedad args en la tarea o el complemento. Al igual que con Maven exec-maven-plugin , se deben pasar en la línea de comando a través de otra propiedad del sistema, como una lista delimitada por espacios que luego se debe split() antes de establecer args , que acepta objetos List . He llamado a la propiedad exec.args , que es el antiguo nombre de Maven.

Parece que tanto el javaExec como el complemento de la aplicación son válidos. Uno podría favorecer el enfoque del complemento de la aplicación si uno quiere usar algunas de sus otras características (armar una distribución automáticamente, etc.)

Aquí están las soluciones:

Enfoque JavaExec

Línea de Comando :

 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() } 

Enfoque del complemento de la aplicación

Línea de Comando :

 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() } 

Para aquellos que no deseen contaminar las propiedades del sistema de su aplicación pasando accesorios Gradle no relacionados, recomiendo el espacio de nombres de sus argumentos.

 tasks.withType(JavaExec) { System.properties.each { k,v-> if (k.startsWith("prefix.")) { systemProperty k - "prefix.", v } } } 

java ... -Dprefix.my.prop=true pasará my.prop

Soy nuevo en Gradle, así que lo necesitaba y lo que funciona para mí con gradle 4.6 parece un poco más fácil para la línea de comandos. En lugar de analizar 1 cadena arg, puede pasar una matriz de args, y encontré una forma de pasar todas las propiedades con una línea también. Combinado a continuación:

 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=