Problemy z przekazywaniem właściwości i parametrów systemowych podczas uruchamiania klasy Java za pośrednictwem Gradle

82

Próbuję uruchomić aplikację Java z wiersza poleceń za pośrednictwem Gradle w ramach szybkiego testu integracji. Przenoszę moje skrypty budowania z Mavena, gdzie można to łatwo zrobić za pośrednictwem exec-maven-plugin. Moje dwa duże wymagania to:

  • Możliwość przekazywania właściwości systemowych do wykonywalnego kodu Java
  • Możliwość przekazywania argumentów wiersza poleceń do wykonywalnego kodu Java

Zwróć uwagę, że nie próbuję odczytać tych właściwości w skrypcie kompilacji, próbuję je odczytać w programie Java, który ten skrypt buduje i wykonuje.

Znalazłem dwa inne stanowiska, tak aby adres Java wykonanie programu przez Gradle: jeden z odpowiedzią, że zwolennicy używając apply plugin: "application"w pliku kompilacji i gradle runw wierszu polecenia , a inna z odpowiedzi promując takie podejście, jak również korzystania task execute(type:JavaExec)z pliku kompilacji i gradle executeu wiersz poleceń . Próbowałem obu podejść i nie udało mi się.

Mam dwa problemy:

(1) Nie mogę pobrać pliku wykonywalnego Java do odczytu właściwości systemu

Czy to robię:

build.gradle :

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

Wiersz poleceń :

gradle run -Dmyproperty=myvalue

Albo to:

build.gradle :

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

Wiersz poleceń :

gradle execute -Dmyproperty=myvalue

W obu przypadkach mypropertynie przechodzi. Kod rozpoczynający się od MyMain.main (...)odczytuje mypropertywłaściwość systemową jako null / brakującą.

(2) Nie mogę przekazać argumentów wiersza poleceń

Jest to prawdopodobnie związane z pierwszym problemem. Na exec-maven-pluginprzykład same argumenty wiersza poleceń były przekazywane przez właściwość systemową. Czy tak jest w przypadku Gradle, czy jest inny sposób przekazywania argumentów wiersza poleceń?

Jak uzyskać dostęp do tych zmiennych? Czy lepiej jest użyć apply plugin: 'application'lub task execute (type:JavaExec)?

sparc_spread
źródło

Odpowiedzi:

124

Domyśliłam się. Głównym problemem jest to, że gdy Gradle tworzy nowy proces Java, nie przekazuje automatycznie wartości zmiennych środowiskowych do nowego środowiska. Należy jawnie przekazać te zmienne za pośrednictwem systemPropertieswłaściwości zadania lub wtyczki.

Inną kwestią było zrozumienie, jak przekazywać argumenty wiersza poleceń; są to argswłaściwości zadania lub wtyczki. Podobnie jak w przypadku Mavena exec-maven-plugin, należy je przekazać w wierszu poleceń za pośrednictwem jeszcze innej właściwości systemowej, jako rozdzieloną spacjami listę, która następnie musi być umieszczona split()przed ustawieniem args, która akceptuje Listobiekty. Nazwałem nieruchomość exec.args, która jest starą nazwą Maven.

Wygląda na to, że zarówno javaExecpodejście, jak i wtyczka aplikacji są prawidłowe. Można faworyzować podejście do wtyczek aplikacji, jeśli chce się korzystać z niektórych innych jej funkcji (automatyczne tworzenie dystrybucji itp.)

Oto rozwiązania:

Podejście JavaExec

Linia poleceń :

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

Podejście wtyczki aplikacji

Linia poleceń :

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
źródło
3
Myślę, że powinno to być System.getProperties () (duże S).
orlanthi
1
Jeśli używasz Gradle 2.xx, można również korzystać z następujących elementów: -systemProperty "myvariable", "${myvariable}"
eadjei
1
Dziękuję Ci! Próbowałem uruchomić testy Cucumber i chciałem przekazać zmienne środowiskowe do JVM. Po prostu umieściłem „systemProperties System.getProperties ()” w teście {} zamiast w uruchomieniu {}
Svante
1
Należy pamiętać, że domyślny podział nie zezwala na argumenty ze spacjami, np. -Dexec.args="--greeting 'hello there'"- nie zadziała, trzeba ustawić inny separator.
Ivan Balashov
3
Użyj: args System.getProperty ("exec.args", "") .split (), aby uniknąć zerowego wyjątku wskaźnika, jeśli nie podano żadnych argumentów. Na przykład nawet `` zadania gradle '' spowodują zgłoszenie wyjątku z sugerowanym build.gradle
Mike Hanafey
12

Dla tych, którzy mogą nie chcieć zanieczyszczać właściwości systemowych aplikacji przez przekazywanie niepowiązanych właściwości Gradle, polecam umieszczanie argumentów w przestrzeni nazw.

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

java ... -Dprefix.my.prop=true przejdzie my.prop

geg
źródło
3

Jestem nowy w gradle, więc potrzebowałem tego i to, co działa dla mnie w gradle 4.6, wydaje się trochę łatwiejsze w linii poleceń. Zamiast analizować 1 ciąg arg, możesz przekazać tablicę argumentów, a ja znalazłem sposób na przekazanie całej właściwości również w jednej linii. Połączone poniżej:

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 Towiański
źródło
-2

Może spóźniłem się na przyjęcie, ale czy ktoś próbował „ustawić rekwizyt przed wykonaniem gradle”? Testowałem i najwyraźniej to też działa.

myVar=myVal gradle test

Na przykład możesz ustawić aktywny profil, taki jak:

SPRING_PROFILES_ACTIVE=dev  gradle test

Te też najwyraźniej działają: (przetestowane)

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

Uważaj, ponieważ myVarnie można oddzielić kropek; w przeciwnym razie tylko część przed pierwszą kropką będzie brana za klucz.

WesternGun
źródło