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

82

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 compilación desde Maven, donde esto se hizo fácilmente a través de exec-maven-plugin. Mis dos grandes requisitos son:

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

Tenga en cuenta que no estoy tratando de leer estas propiedades en el script de compilación, estoy tratando de leerlas en el programa Java que el script construye y ejecuta.

Encontré otras dos publicaciones SO que abordan la ejecución del programa Java a través de Gradle: una con una respuesta que aboga por el uso apply plugin: "application"en el archivo de compilación y gradle runen la línea de comando , y otra con respuestas que abogan por ese enfoque, así como task execute(type:JavaExec)en el archivo de compilación y gradle executeen el línea de comando . He probado ambos enfoques y no he tenido éxito.

Tengo dos problemas:

(1) No puedo hacer que el ejecutable de Java lea 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, mypropertyno lo logra. El código que comienza a ejecutarse MyMain.main (...)lee la mypropertypropiedad del sistema como nulo / perdido.

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

Probablemente esto esté relacionado con el primer problema. En exec-maven-plugin, por ejemplo, los argumentos de la línea de comandos 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 hago pasar estas variables? Además, ¿es mejor usar apply plugin: 'application'o task execute (type:JavaExec)?

sparc_spread
fuente

Respuestas:

123

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

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

Parece que tanto el javaExecenfoque del complemento como el de la aplicación son válidos. Uno podría favorecer el enfoque de complemento de la aplicación si desea utilizar algunas de sus otras características (armar automáticamente una distribución, 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 de complemento de 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()    
}
sparc_spread
fuente
3
Creo que debería ser System.getProperties () (mayúscula S).
orlanthi
1
Si está utilizando gradle 2.xx, también puede utilizar lo siguiente: -systemProperty "myvariable", "${myvariable}"
eadjei
1
¡Gracias! Intenté ejecutar pruebas de Cucumber y quería pasar variables de entorno a la JVM. Acabo de poner "systemProperties System.getProperties ()" en prueba {} en lugar de ejecutar {}
Svante
1
Tenga en cuenta que la división predeterminada no permite argumentos con espacios, por ejemplo -Dexec.args="--greeting 'hello there'", no funcionará, es necesario establecer otro delimitador.
Ivan Balashov
3
Utilice: args System.getProperty ("exec.args", "") .split () para evitar la excepción de puntero nulo si no se proporcionan argumentos. Por ejemplo, incluso las 'tareas de gradle' arrojarán una excepción con la build.gradle sugerida
Mike Hanafey
12

Para aquellos que no quieran contaminar las propiedades del sistema de su aplicación al pasar accesorios de Gradle no relacionados, recomiendo espaciar 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

geg
fuente
3

Soy nuevo en gradle, así que necesitaba esto y lo que me funciona con gradle 4.6 parece un poco más fácil para la línea de comandos. En lugar de analizar una cadena de argumentos, puede pasar una matriz de argumentos, y encontré una manera 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=
Stan Towianski
fuente
-2

Tal vez llego tarde a la fiesta, pero ¿alguien ha intentado "configurar el accesorio antes de ejecutar gradle"? Lo he probado y esto también funciona, aparentemente.

myVar=myVal gradle test

Por ejemplo, puede configurar el perfil activo como:

SPRING_PROFILES_ACTIVE=dev  gradle test

Estos también funcionan, aparentemente: (probado)

set myVar=myVal && gradle test      # for windows
export myVar=myVal && gradle test   # for linux and mac

Tenga cuidado de que myVarno se puedan separar períodos; o de lo contrario, solo se tomará como clave la parte anterior al primer período.

WesternGun
fuente