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.
Related
Gradle Version: 1.12/2.0 (restricted due to Org policies)
JDK: 1.8
I have created a custom gradle plugin that performs some installation using code that has been defined in another sub-project of our source-code. The build.gradle for the plugin is
dependencies {
compile project(path: ':installlib', configuration: 'libConfig')
compile project(path: ':tools', configuration: 'toolConfig')
}
jar {
from {
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
baseName = 'myCustomPlugin'
version = '1.0'
destinationDir = new File(project.libDir)
}
The above plugin is consumed as follows - consumer.gradle
buildscript {
repositories { flatDir name: 'libs', dirs: System.env.CODESOURCE + '/lib/')
dependencies {
classpath: ':myCustomPlugin:1.0'
}
}
apply plugin: 'java'
apply plugin: 'myCustomPlugin'
...
...
//rest of the items of this gradle
Case-A
If I run this, I hit > Plugin with id 'myCustomPlugin' not found.
NOTE: I have META-INF/gradle-plugins/myCustomPlugin.properties created correctly with implementation-class pointing to my plugin code and this works fine if I don't get into creating the fat/uber-jar business and just include the sourceSets.main.output statement in my jar task. But since our entire project depends on file based artifacts, I am attempting to create a fat/uber-jar and that's where I start running into these issues.
Case-B
If I move the LINE#2 above the LINE#1, which looks like -
from {
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
}
If I run this, I hit ClassNotFoundException for one of the classes coming from the project 'installlib'. I can see the *.class file in the uber jar created but even then the class loader complains about this class.
Could anyone provide some pointers on how to resolve this ? The uber/fat jar creation (or the way I am doing it) is not helping with the plugin-source-code and dependencies of the plugin.
If not a fat jar, could anyone provide some inputs on how to resolve the dependencies in the buildscript of the consuming gradle ?
I can run my project using gradle run, but I can't run the jar file using java -jar. I've recreated the error with this sample project: link to project on GitHub
This is the output from running the project via gradlew
$ ./gradlew run
> Task :run
Hello world.
BUILD SUCCESSFUL in 4s
This is the output from running the project java -jar
$ ./gradlew build
BUILD SUCCESSFUL in 6s
$ java -jar build/libs/emailer.jar
Error: Could not find or load main class us.company.emailer.App
But when I unzip the jar, I can see App.class
user#computer:../libs$ unzip emailer.jar
Archive: emailer.jar
creating: META-INF/
inflating: META-INF/MANIFEST.MF
creating: us/
creating: us/company/
creating: us/company/emailer/
inflating: us/company/emailer/App.class
Here's the build.gradle
plugins {
id 'groovy'
id 'application'
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
implementation 'org.codehaus.groovy:groovy-all:2.5.6'
testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
compile 'org.apache.commons:commons-email:1.5'
}
mainClassName = 'us.company.emailer.App'
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'us.company.emailer.App'
)
}
}
sourceSets.main.java.srcDirs = ['src/main/groovy']
Here's the App.groovy
package us.company.emailer
class App {
String getGreeting() {
return 'Hello world.'
}
static void main(String[] args) {
println new App().greeting
}
}
EDIT: Adding MANIFEST.MF in response to the comment from #tkruse
Manifest-Version: 1.0
Class-Path: commons-email-1.5.jar javax.mail-1.5.6.jar activation-1.1.
jar
Main-Class: us.company.emailer.App
The problem is the classpath. If you look inside the META-INF/MANIFEST.mf file, you can see it's set to:
Class-Path: commons-email-1.5.jar javax.mail-1.5.6.jar activation-1.1.
jar
When java runs, it has no idea where any of these things are, it also requires the groovy runtime in order to understand your groovy code.
The simplest way of doing this is to bundle all your dependencies into a "fat-jar", and the simplest way of doing this with Gradle is the excellent Shadow-jar plugin.
If you add the following to your plugins block in build.gradle:
id 'com.github.johnrengelman.shadow' version '5.0.0'
(You can delete the jar block and the line that manipulates the sourceSets)
Then run ./gradlew shadowJar
You'll get a jar file emailer-all.jar
Which can be run:
$ java -jar build/libs/emailer-all.jar
Hello world.
For completeness, here's the complete build.gradle file:
plugins {
id 'groovy'
id 'application'
id 'com.github.johnrengelman.shadow' version '5.0.0'
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
implementation 'org.codehaus.groovy:groovy-all:2.5.6'
testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
implementation 'org.apache.commons:commons-email:1.5'
}
mainClassName = 'us.company.emailer.App'
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.
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
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