Gradle Output Jar has no Main-Class - java

I have the following simple build.gradle file:
apply plugin: 'application'
apply plugin: 'java'
mainClassName = 'com.kurtis.HelloGradle'
And the following single java file located at src/main/java/com/kurtis/HelloGradle.java:
package com.kurtis;
public class HelloGradle {
public static void main(String[] args) {
System.out.println("Hello gradle");
}
}
However, if I run gradle build I get a jar in the build/lib directory that has no main class set. It's manifest file has no Main-Class entry. Why is this?

It's due to the way application plugin works. mainClassName is a property used by application plugin, when it creates an executable jar, it doesn't need to have a Main-Class in the manifest, since it doesn't use it.
If you need to have a Main-Class in your jar, then you have to provide it vie jar configuration of the java plugin as follows:
jar {
manifest {
attributes(
'Main-Class': 'com.kurtis.HelloGradle'
)
}
}
Otherwise, just use an executable, which is generated by application plugin, whether via run task or via distributions it can create for you, with scripts to run your application and all it's dependencies.

Related

Create a Jar file with dependencies from settings.gradle

I want to create a jar file which can be used by command like java -cp .\TrendAnalyzer.jar trend_detect.Main.
However, I can't find a way to create a jar file from settings.gradle, not build.gradle.
How can I create a jar file with dependencies from settings.gradle, which contains include etc. information.
Add com.github.johnrengelman.shadow plugin to main module build.jar
plugins {
// *snip*
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
application {
// Define the main class for the application.
mainClass = 'jaso92559.app.App'
}
jar {
manifest {
// Define the main class for the application.
attributes "Main-Class": "jaso92559.app.App"
}
}
run ./gradle shadowJar command on the path where settings.gradle exists.
In app\build\libs, app-all.jar file is generated and it can be run java -jar app-all.jar.
According to https://github.com/yukihane/stackoverflow-qa/tree/main/jaso92559
To create a jar file from settings.gradle, you can use the jar task in Gradle. This task allows you to package the compiled code and any dependencies into a jar file, which can then be executed using the java command with the -cp option.
Creating a jar file using the jar task in settings.gradle:
// settings.gradle
include ':trend_detect'
// build.gradle (in the trend_detect module)
apply plugin: 'java'
jar {
manifest {
attributes 'Main-Class': 'trend_detect.Main'
}
from {
configurations.compile.collect {
it.isDirectory() ? it :
zipTree(it) }
}
}
The include statement in settings.gradle specifies that the trend_detect module should be included in the build.
In the build.gradle file for the trend_detect module, the jar task is defined to create a jar file with a MANIFEST.MF file that specifies the main class (trend_detect.Main). The from statement in the jar task specifies that the jar file should include all of the compiled code and dependencies from the compile configuration.
Once the jar file has been created, you can run it using the java command with the -cp option, as follows:
java -cp .\TrendAnalyzer.jar trend_detect.Main
This will execute the main() method in the trend_detect.Main class, using the compiled code and dependencies contained in the jar file.

Tasks for build and run works but executing with the generated run script doesn't

I am doing the simple HelloWorld example from https://spring.io/guides/gs/gradle/.
I had to do some changes (I'm using Gradle 5.2.1 on Ubuntu 18) to the build.gradle. I used gradlew wrapper. I managed to get tasks like 'build' and 'run' working. Everything is generated correctly, it seems. But running the app without gradle using the generated build/scripts/<appscript> does not work. Running the jar with
java -jar build/libs/hello-1.0.jar
works. But
./build/scripts/sayhello
Does not work and produces an error:
erno#moongate:~/Projects/java/sayhello$ ./build/scripts/sayhello
Error: Could not find or load main class hello.HelloWorld
Caused by: java.lang.ClassNotFoundException: hello.HelloWorld
Project file structure is as suggested:
sayhello/
build.gradle
gradlew
src/
main/
java/
hello/
Greeter.java
HelloWorld.java
I had to add the manifest and the mainclass attribute to the build configuration file as it seems that the gradle init --type java-application does not do it. Meaning that even trying to run the gradle generated base project does not work.
My build.gradle is like this:
plugins {
id 'java'
id 'application'
}
mainClassName = 'hello.HelloWorld'
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile "joda-time:joda-time:2.10"
testCompile "junit:junit:4.12"
}
jar {
manifest {
attributes(
'Main-Class': 'hello.HelloWorld'
)
}
baseName = 'hello'
version = '1.0'
}
The problem with the startScripts task is that it generates a very basic script. It does not make sure dependent jars are in the right places - it expects this to be done by you. Also it assumes that you will be running the script from a directory it refers to as the $APP_HOME and this folder needs to contain a lib folder which contains all the jars your app needs.
My very hacky solution is to generate an even more basic unix script instead of relying on the default one.
startScripts {
dependsOn jar
doFirst {
unixStartScriptGenerator = configure(new CustomUnixStartScript()) {
classpath = configurations.runtimeClasspath + jar.outputs.files
}
}
}
class CustomUnixStartScript implements ScriptGenerator {
#InputFiles
FileCollection classpath
#Override
void generateScript (JavaAppStartScriptGenerationDetails details, Writer destination) {
destination << """java -classpath $classpath.asPath ${details.mainClassName}"""
}
}
You can extend this as you see fit.

Cannot execute jar built with gradle with correct Manifest

I have a JavaFx application and I cannot run it from both command line and windows explorer.I built the jar using Gradle, and checked for the manifest and it is correct. I tried everything from StackOverflow but it always complains that it cannot find the entry point from Manifest:
My main is located in src/main/java and it is called Main.
Here is the configuration for gradle:
group 'com'
version '1.0'
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 1.8
mainClassName = 'Main'
repositories {
mavenCentral()
}
jar {
manifest {
attributes('Main-Class': 'Main')
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Please ignore the dependecies (I build an uber jar).
And here is the content of my manifest(created by gradle with the new line at the end):
Manifest-Version: 1.0
Main-Class: Main
When I try to run it i get all the time this:
Error: Could not find or load main class Main
Because you apply the application plugin, none of the customisations of the jar tasks are required.
So I recommend you remove them and check if it creates a valid jar then.
While I did not confirm by running it locally, I believe the customisation done in from is wrong and creates a busted jar.

gradle project: error couldn't find main class

I have the following project structure:
Root project 'rmi-tutorial'
+--- Project ':client'
+--- Project ':lib'
\--- Project ':server'
The path to clients main class looks like this:
client/src/main/java/client/ComputePi.java
my build.gradle for the client subproject loooks like this:
dependencies {
compile project(':lib')
}
mainClassName = "ComputePi"
The main build.gradle file is this one:
subprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
repositories {
mavenCentral()
}
dependencies {
//compile project(':server')
//compile project(':client')
testCompile 'junit:junit:4.12'
}
version = '1.0'
jar {
manifest.attributes provider: 'gradle'
}
}
The generation of the jars works so far but the MANIFEST.MF file in the jar is wrong. It contains the following:
Manifest-Version: 1.0
provider: gradle
Where is my specified main class? When I try to execute the startscript that got created by the gradle application-plugin I get the error: couldn't find nor load main class
The jar contains all necessary class files
The application plugin does not produce a runnable JAR with Main-Class entry. Instead it generates a distribution with Windows and *nix start scripts where the main class is used and all libaries put to the class path.
If you want a runnable JAR, you have to configure it yourself, or use one of the plugins that produces a fat JAR, also including the dependencies into the runnable JAR (I don't like this, but it works if the target computer has the correct file associations set). If the target computer e. g. has associated JAR files with an archiving tool, double-clicking the JAR will open the JAR in the archiving tool, not run your application.
If you want to run your application, use gradlew run, or do gradlew installDist and then execute the application that is installed to build/install/.... That is how the application plugin works. With gradlew distZip or gradlew distTar you can create shippable archives of your application.

Gradle custom task for jar

I am using Gradle for my Java project and I was wondering if it's possible to prevent gradle build from creating a jar file each time executed.
Also, is it possible to have a custom task for creating the Jar with dependencies at a specific location build/myAppJar/.
Here's what I have so far for the custom task:
task toJar (type: Jar) {
from configurations.compile.collect { zipTree it }
manifest {
attributes 'Implementation-Title': 'myApp',
'Implementation-Version': 1.0,
'Main-Class': mainClassName
}
}
The above code will create the jar file under build/libs, and the file does not contain the compiled files, only the dependencies.
Thank you!
The build task comes from the java plugin. You can control when a jar is built with something like this:
jar {
onlyIf { condition }
}
You can set jar to be built when you declare something else to be true, or hard set it to false to never build a jar.
You can include sourcesets in your toJar custom task, to include compiled files into your jar.
task toJar (type: Jar) {
from sourceSets.all
}
You are explicitly calling for all compile time dependencies to be included in the jar here: from configurations.compile.collect
ref: Gradle java plugin

Categories

Resources