Gradle для выполнения класса Java (без изменения build.gradle)

119

Есть простой плагин Eclipse для запуска Gradle, который просто использует способ командной строки для запуска gradle.

Что такое аналог Gradle для компиляции и запуска maven mvn compile exec:java -Dexec.mainClass=example.Example

Таким образом gradle.buildможно запустить любой проект с .

ОБНОВЛЕНИЕ: был аналогичный вопрос. Что такое gradle-эквивалент плагина maven exec для запуска приложений Java? спрашивали раньше, но решение предлагало изменить каждый проектbuild.gradle

package runclass;

public class RunClass {
    public static void main(String[] args) {
        System.out.println("app is running!");
    }
}

Затем выполнение gradle run -DmainClass=runclass.RunClass

:run FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> No main class specified   
Пол Верест
источник
Вероятный дубликат stackoverflow.com/questions/16350757/…
Тереза ​​Карриган
Используйте команду: gradle run
a_subscriber

Ответы:

138

Нет прямого эквивалента mvn exec:javaв gradle, вам нужно либо применить applicationплагин, либо иметь JavaExecзадачу.

application плагин

Активируйте плагин:

plugins {
    id 'application'
    ...
}

Настройте его следующим образом:

application {
    mainClassName = project.hasProperty("mainClass") ? getProperty("mainClass") : "NULL"
}

В командной строке напишите

$ gradle -PmainClass=Boo run

JavaExec задача

Определите задачу, скажем execute:

task execute(type:JavaExec) {
   main = project.hasProperty("mainClass") ? getProperty("mainClass") : "NULL"
   classpath = sourceSets.main.runtimeClasspath
}

Чтобы запустить, напишите gradle -PmainClass=Boo execute. Ты получаешь

$ gradle -PmainClass=Boo execute
:compileJava
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes
:execute
I am BOO!

mainClass- это свойство, динамически передаваемое в командной строке. classpathнастроен на получение последних классов.


Если вы не передадите mainClassсвойство, оба подхода потерпят неудачу, как ожидалось.

$ gradle execute

FAILURE: Build failed with an exception.

* Where:
Build file 'xxxx/build.gradle' line: 4

* What went wrong:
A problem occurred evaluating root project 'Foo'.
> Could not find property 'mainClass' on task ':execute'.
Первый ноль
источник
1
Вы должны изменить build.gradle, classpathон жестко запрограммирован для получения классов java из пути к исходным классам build.gradle java . Даже когда вы запускаете путь mvn exec:javaк классам, он настроен на получение исходных файлов java в текущем каталоге maven. В JavaExecзадаче я сделал то же самое. Измените classpathдля своего источника java, и путь к классу изменится автоматически. Нет mvn exec:javaэквивалента в том, что gradleвам нужно либо применить applicationплагин, либо иметь JavaExecзадачу.
First Zero
1
ИЛИ другой вариант: вы пишете свой собственный плагин для этого, и даже тогда вам нужно изменить build.gradle, чтобы подобрать свой плагин.
First Zero
3
Я просто попробовал это, и кажется, что после добавления task execute(...в build.gradle все остальные задачи завершаются сбоем с тем же сообщением об ошибке, говорящим, что gradle ожидает передачи mainClass. Я не умею убирать или строить.
Nirro
4
@Nirei Замените main = mainClassна, main = getProperty("mainClass")и он больше не будет на вас кричать.
Ади Гербер
2
это все еще ломается gradle build, см. мой ответ ниже.
Мэтт
140

Вам просто нужно использовать плагин Gradle Application :

apply plugin:'application'
mainClassName = "org.gradle.sample.Main"

А потом просто gradle run.

Как указывает Тереза, вы также можете настроить mainClassNameкак системное свойство и запускать с аргументом командной строки.

Видья
источник
2
Это потребует жесткого кодирования каждого такого класса в build.graldle. Но у меня есть проект с множеством утилитарных классов, у каждого из которых есть основной метод.
Пол Верест
И вы уверены: 1) полное имя класса верно 2) вы указываете правильное имя свойства в файле сборки - например System.getProperty("mainClass") , 3) исходный код находится там, где он должен быть в соответствии с соглашением, 4) все работает когда вы вставляете RunClassфайл сборки?
Vidya
Это работает, только если build.gradleесть mainClassName = "runclass.RunClass". Параметр -DmainClassне действует: gradle run -DmainClass=runclass.RunClass2выполняет жестко запрограммированный основной класс.
Пол Верест,
3
Если вы делаете и то, и другое (подход к созданию файла и подход к свойствам), я на самом деле не знаю, что имеет приоритет. Вы должны либо найти этот ответ, либо не делать то и другое в ходе тестирования.
Vidya
2
@PaulVerest Вот что я сделал: ext.mainClass = project.hasProperty('mainClass') ? project.getProperty('mainClass') : 'org.gradle.sample.Main' ; apply plugin:'application' ; mainClassName = ext.mainClass теперь, когда вы это делаете, gradle -PmainClass=Foo runон должен использоваться Fooв качестве основного класса.
msridhar 06
26

Расширяя ответ First Zero, я думаю, вам нужно что-то, где вы также можете работать gradle buildбез ошибок.

Оба gradle buildи gradle -PmainClass=foo runAppработают с этим:

task runApp(type:JavaExec) {
    classpath = sourceSets.main.runtimeClasspath

    main = project.hasProperty("mainClass") ? project.getProperty("mainClass") : "package.MyDefaultMain"
}

где вы устанавливаете основной класс по умолчанию.

Matt
источник
2
Имхо, это должен быть принятый ответ. Использование метода FirstZero или Vidya приведет к тому, что другие задачи будут жаловаться на то, что основной класс не указан.
янхан
Подход Мэтта к установке основного значения также работает для плагина приложения. Я использую его с Gradle Kotlin DSL: plugins { application }; application { mainClassName = if (project.hasProperty("mainClass")) project.properties.get("mainClass").toString() else "Foo" }
pvillela
@Matt Этот подход нарушает мою простую программу на Java, в которой Scannerдля чтения используется a nextLine(). Есть какие-нибудь мысли по исправлению этого? Продолжайте получать сообщение «строка не найдена» при запуске с помощью runApp.
Грег Хилстон
2
Для всех, кто читает это в будущем, я использовал `standardInput = System.in`, чтобы позволить моему выполнению gradle по-прежнему проходить на входе
Грег Хилстон,
0

Вы можете параметризовать его и передать gradle clean build -Pprokey = goodbye

task choiceMyMainClass(type: JavaExec) {
     group = "Execution"
    description = "Run Option main class with JavaExecTask"
    classpath = sourceSets.main.runtimeClasspath

    if (project.hasProperty('prokey')){
        if (prokey == 'hello'){
            main = 'com.sam.home.HelloWorld'
        } 
        else if (prokey == 'goodbye'){
            main = 'com.sam.home.GoodBye'
        }
    } else {
            println 'Invalid value is enterrd';

       // println 'Invalid value is enterrd'+ project.prokey;
    }
Самира Де Силва
источник