Gradle 'application' plugin - is it possible to specify which mainClassName to use? - java

I want to be able to choose which main class I run using gradle at the command line using the application plugin.
For example, suppose I have two adjacent apps under /src.
I simply want to run gradle run firstApp or gradle run secondApp and have the mainClassName be specified by the tasks:
task firstApp {
mainClassName = 'com.example.firstApp'
}
task secondApp {
mainClassName = 'com.example.secondApp'
}
Is this possible? Unfortunately, it always defaults to the secondApp in this configuration. I am sure I am doing silly gradle mistakes.

Try this:
task firstApp(type:JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'com.example.firstApp'
}
task secondApp(type:JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'com.example.secondApp'
}

Related

How to run shadow jar with a gradle task?

I want to run my app after building it with the shadow jar plugin.
build.gradle:
plugins {
id 'java'
id "org.jetbrains.kotlin.jvm" version "1.3.21"
id "com.github.johnrengelman.shadow" version "5.0.0"
}
group 'org.example.java'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
repositories {
jcenter()
}
dependencies {
compile "io.ktor:ktor-server-netty:1.1.3"
}
I also have a global init.gradle:
gradle.projectsLoaded {
rootProject.allprojects {
buildDir = "/Users/User/Builds/${rootProject.name}/${project.name}"
}
}
So now the fat jar can be built to my global build directory with the shadowJar task. But I want to be able to run and build it with just one run configuration in IntelliJ. How do I do that?
Maybe there is another way to let gradle redirect all my output to a global build directory. I don't want to configure each IntelliJ project with the same output path manually. Suggestions are welcome.
Thank you :)
You should not touch the buildDir property for achieving what you want.
Instead, you should create a JavaExec task that will start the application from the shadow jar.
If you want that execution to be at a different place than the default location of the generated jar, you should either change the output of the shadow task itself, and only that output or make your execution task depend on a copy task that would move the shadow jar around.
Something like:
shadowJar {
destinationDir = "/Users/User/Builds/${rootProject.name}/${project.name}"
}
task runApp(type: JavaExec) {
main = "your.main.Class
classpath = shadowJar.archiveFile // use archivePath before Gradle 5.1
}

Gradle subproject installDist dependency

I have a project with two subprojects, and am having problems getting the installDist to recognise when it is up-to-date. I have a main build.gradle for the project projName, which has a subproject subproj1 which compiles fine, and another subproject exec which has the following tasks:
task makeMyExec(type: Copy) {
dependsOn(':projName.exec:installDist')
copy {
from rootProject.file("projName/build/install/exec/")
into rootProject.file("../myExec/")
}
}
def createScript(project, mainClass, name) {
project.tasks.create(name: name, type: CreateStartScripts) {
outputDir = new File(project.buildDir, 'scripts')
mainClassName = mainClass
applicationName = name
classpath =
project.tasks[JavaPlugin.JAR_TASK_NAME].outputs.files +
project.configurations.runtime
}
project.tasks[name].dependsOn(project.jar)
project.applicationDistribution.with {
into("bin") {
from(project.tasks[name])
fileMode = 0755
}
}
}
Then in the subproject exec I have the following lines of its build.gradle
apply plugin: 'application'
dependencies {
compile project(':subproj1')
}
startScripts.enabled = false
run.enabled = false
createScript(project, 'projName.exec.exec1Main', 'script1')
createScript(project, 'projName.exec.exec2Main', 'script2')
createScript(project, 'projName.exec.exec3Main', 'script3')
The idea is that each of the scripts script1, script2 and script3 should be added to the installDist of subproject exec, so that they need to be created before the copy command runs. Unfortunately the copy command always run first.
This means if I run this twice everything copies properly and I get the scripts in the right place, but unfortunately not if I run it just once.
I would very much appreciate help working out what I have wrong with the dependency here, either the dependency on subproj1 in exec, or the dependency of installDist in the makeMyExec task.
For info - if I only have one mainClass in the subproject and define only
mainClassName ='projName.exec.exec1Main'
applicationName = 'script1'
then this works as intended and all the libs and scripts are built before the copy is done, as the dependency on installDist seems to work then.
I have now found the solution to this problem. If I modify the makeMyExec task to:
task makeMyExec(type: Copy) {
dependsOn('installDist','script1','script2','script3')
from rootProject.file("projName/build/install/exec/")
into rootProject.file("../myExec/")
}
this remove the necessity for the line:
project.tasks[name].dependsOn(project.jar)
and adds the dependency to the copy task of the installDist of the main project and each of the subtasks script1, script2 and script3.
My mistake was to misunderstand that the project.applicationDistribution.with did not actually update the status of :projName.exec:installDist

using Kotlin with Gradle

I'm new to Kotlin and Gradle, and tried to follow these steps, so I got the following 2 files:
after running gradle init I changed the build.gradle to be:
// set up the kotlin-gradle plugin
buildscript {
ext.kotlin_version = '1.1.2-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// apply the kotlin-gradle plugin
apply plugin: "kotlin"
apply plugin: 'application'
mainClassName = "hello.main"
// add kotlin-stdlib dependencies.
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
Hello.kt:
package hello
fun main(args: Array<String>) {
println("Hello World!")
}
Then I run the gradle build and got the build\classes\main\hello\HelloKt.class
my question is: Why the file generated is .class not .jar and how to get the .jar file and how to run it, I tried running the generated file using kotlin -classpath HelloKt.class main but got an error error: could not find or load main class hello.main
The classes are the direct output of the Kotlin compiler, and they should be packaged into a JAR by Gradle afterwards. To build a JAR, you can run the jar task, just as you would in a Java project:
gradle jar
This task is usually run during gradle build as well, due to the task dependencies.
This will pack the Kotlin classes into a JAR archive (together with other JVM classes, if you have a multi-language project), normally located at build/libs/yourProjectName.jar.
As to running the JAR, see this Q&A for a detailed explanation: (link)
Thanks for #hotkey answer, it helped me going the correct way.
First of all there is a mistake in the main class declaration, as it should follow the new methodology, that is in the below format:
mainClassName = '[your_namespace].[your_arctifact]Kt'
namespace = package name
arctifact = file name
so, considering the names given in the example above where filename is: Hello.kt, and the namespace is hello, then:
mainClassName = `[hello].[Hello]Kt`
using the previous method, that contains:
apply plugin: 'application'
mainClassName = 'hello.HelloKt'
the generated .jar file is not including the kotlin runtime, so the only way to execute it, is by:
d:/App/build/libs/kotlin -cp App.jar hello.HelloKt
but in order to generate a self contained jar that can be self-executed, and contains the kotlin runtime then the build.gradle should be written as:
// set up the kotlin-gradle plugin
buildscript {
ext.kotlin_version = '1.1.2-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// apply the kotlin-gradle plugin
apply plugin: "kotlin"
// add kotlin-stdlib dependencies.
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
jar {
manifest {
//Define mainClassName as: '[your_namespace].[your_arctifact]Kt'
attributes 'Main-Class': 'hello.HelloKt'
}
// NEW LINE HERE !!!
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
followed by gradle build, the [your_working_folder].jar file will be generated at the build/libs folder, assuming the working folder name is app, then file app.jar will be generated.
To run this file, one of the following 2 commands can be used:
D:\App\build\libs\java -jar App.jar
OR
D:\App\build\libs\kotlin App.jar hello.HelloKt

Gradle error with lack of mainClassName property in gradle build

I have graddle configuration with two subprojects and when I want do build the project the following error is thrown:
Executing external task 'build'...
:core:compileJava
:core:processResources UP-TO-DATE
:core:classes
:core:jar
:core:startScripts FAILED
FAILURE: Build failed with an exception.
* What went wrong:
A problem was found with the configuration of task ':core:startScripts'.
> No value has been specified for property 'mainClassName'.
My configuration:
ROOT - build.gradle:
subprojects {
apply plugin: 'java'
apply plugin: 'application'
group = 'pl.morecraft.dev.morepianer'
repositories {
mavenLocal()
mavenCentral()
}
run {
main = project.getProperty('mainClassName')
}
jar {
manifest {
attributes 'Implementation-Title': project.getProperty('name'),
'Implementation-Version': project.getProperty('version'),
'Main-Class': project.getProperty('mainClassName')
}
}
}
task copyJars(type: Copy, dependsOn: subprojects.jar) {
from(subprojects.jar)
into project.file('/jars')
}
ROOT - setting.gradle:
include 'app'
include 'core'
APP PROJECT - build.gradle:
EMPTY
CORE PROJECT - build.gradle:
dependencies {
compile 'com.google.dagger:dagger:2.4'
compile 'com.google.dagger:dagger-compiler:2.4'
}
AND BOTH SUBPROJECTS (SIMILAR) - gradle.properties:
version = 0.1-SNAPSHOT
name = MorePianer Core Lib
mainClassName = pl.morecraft.dev.morepianer.core.Core
I've tried to add the mainClassName property in many places, but it does not work. This is even stranger, that It worked a couple days ago as it is. I'm using gradle for first time and I'm thinking about switching back to maven.
The application plugin needs to know the main class for when it bundles the application.
In your case, you apply the application plugin for each subproject without specifying the main class for each of those subprojects.
I had the same problem and fixed it by specifying "mainClassName" at the same level as apply plugin: 'application' :
apply plugin: 'application'
mainClassName = 'com.something.MyMainClass'
If you want to specify it in the gradle.properties file you might have to write it as : projectName.mainClassName = ..
Instead of setting up mainClassName try to create
task run(type: JavaExec, dependsOn: classes) {
main = 'com.something.MyMainClass'
classpath = sourceSets.main.runtimeClasspath
}
Please look at Gradle fails when executes run task for scala
Whenever we bind a gradle script with the application plugin, Gradle expects us to point out the starting point of the application. This is neccessary because, Gradle will start bundling your application (jar/zip) using the given location as the entry point.
This error is thrown simply because Gradle knows that you want to bundle your application but is clueless about where to start the bundling process.
One can specify the mainClassName as a project extended property:
ext {
mainClassName = 'com.something.MyMainClass'
}
I faced the same issue in my project and solved it by excluding from gradle.properties:
#ogr.gradle.configurationdemand = true

how to run after compiling thru gradle?

I am using the java plugin in my build.gradle.
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'xyz:xyz:4.11'
}
sourceSets {
test {
java {
srcDir 'agent'
}
}
}
I am generating the .class files by doing
$ gradle compileJava
Now that the .class files have been generated in build/, how do I run my code? One of the class files contains the main. I want to do something like this from a gradle task:
CLASSPATH=./mysql-connector-java-commercial-5.1.13-bin.jar:. $JAVA_HOME/bin/java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10000 Collector arg1
You may want to take a look at Gradle Application Plugin.
With it, you will be able to run your application just using a run task.
Based on ghik's answer, I add these to my gradle.build script:
apply plugin:'application'
....
dependencies {
....
runtime 'mysql:mysql-connector-java-commercial:5.1.13'
}
mainClassName = "Collector"
run {
args 'arg1'
jvmArgs '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10000'
}

Categories

Resources