Problemas na passagem de propriedades e parâmetros do sistema ao executar a class Java via Gradle

Eu estou tentando executar um aplicativo Java de linha de comando via Gradle como parte de um teste de integração rápida. Estou portando meus scripts de construção do Maven, onde isso era feito facilmente via exec-maven-plugin . Meus dois grandes requisitos são:

  • Ser capaz de passar as propriedades do sistema para o código Java executável
  • Ser capaz de passar argumentos de linha de comando para o código Java executável

Por favor note que eu não estou tentando ler estas propriedades no script de construção, estou tentando lê-las no programa Java que o script constrói e executa.

Eu encontrei dois outros posts SO que abordam a execução do programa Java via Gradle: um com uma resposta que defende o uso do apply plugin: "application" no arquivo de compilation e gradle run na linha de comando , e outro com respostas defendendo essa abordagem, bem como usando task execute(type:JavaExec) no arquivo de compilation e gradle execute na linha de comando . Eu tentei ambas as abordagens e não consegui.

Eu tenho dois problemas:

(1) Não consigo fazer com que o executável Java leia as propriedades do sistema

Se eu faço isso:

build.gradle :

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

Linha de comando :

 gradle run -Dmyproperty=myvalue 

Ou isto:

build.gradle :

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

Linha de comando :

 gradle execute -Dmyproperty=myvalue 

Em ambos os casos, myproperty não consegue passar. O código que começa a ser executado a partir do MyMain.main (...) lê a propriedade do sistema myproperty como null / missing.

(2) não consigo passar argumentos de linha de comando

Isso provavelmente está relacionado ao primeiro problema. No exec-maven-plugin , por exemplo, os argumentos da linha de comando foram passados ​​por meio de uma propriedade do sistema. É esse o caso de Gradle, ou existe outra maneira de passar argumentos de linha de comando?

Como obtenho essas variables? Além disso, é melhor usar o apply plugin: 'application' ou task execute (type:JavaExec) ?

Descobri isso. A questão principal é que, quando o Gradle forks em um novo processo Java, ele não passa automaticamente os valores da variável de ambiente para o novo ambiente. É preciso passar explicitamente essas variables ​​pela propriedade systemProperties da tarefa ou do plug-in.

A outra questão era entender como passar argumentos de linha de comando; estes são através da propriedade args na tarefa ou plugin. Como com o Maven exec-maven-plugin , eles devem ser passados ​​na linha de comando através de outra propriedade do sistema, como uma lista delimitada por espaço que precisa ser split() antes de definir args , que aceita objects List . Eu nomeei a propriedade exec.args , que é o nome antigo do Maven.

Parece que tanto o javaExec quanto a abordagem do plug-in de aplicativo são válidos. Pode-se favorecer a abordagem do plugin de aplicação, se alguém quiser usar alguns de seus outros resources (colocando automaticamente uma distribuição, etc.)

Aqui estão as soluções:

Abordagem JavaExec

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

Abordagem de Plugins de Aplicativos

Linha 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 aqueles que talvez não queiram poluir as propriedades do sistema do seu aplicativo, passando propulsos não relacionados de Gradle, recomendo que você classifique seus argumentos.

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

java ... -Dprefix.my.prop=true irá passar my.prop

Eu sou novo para gradle então eu precisava disso e o que está funcionando para mim com gradle 4.6 parece um pouco mais fácil para a linha de comando. Em vez de analisar 1 arg string você pode passar um array de args, e eu encontrei uma maneira de passar em toda propriedade com uma linha também. Combinado abaixo:

 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=