Gradle : Could not find or load main class - java

Here is my tree files :
src
--JaJson.java
build.gradle
Here is my JaJson.java:
public class JaJson {
public static void main(String args[]) {
System.out.println("Hello");
}
public JaJson(){
System.out.println("what time is it ?");
}
public void getTime(){
System.out.println("Hammer time!");
}
}
Here is my gradle.build :
apply plugin: 'java'
apply plugin: 'eclipse'
//apply plugin: 'java-library'
apply plugin: 'application'
mainClassName = "JaJson"
// tag::repositories[]
repositories {
mavenCentral()
}
// end::repositories[]
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
sourceSets {
single{
java {
srcDir 'src'
}
}
}
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'JaJson'
)
}
}
task compileSingle(type: JavaCompile) {
source = sourceSets.single.java
sourceSets.main.java.srcDirs = ['src']
classpath = sourceSets.main.compileClasspath
destinationDirectory = sourceSets.main.output.classesDirs[0]
}
compileJava {
options.release = 7
}
version = '1.2.1'
// tag::dependencies[]
dependencies {
implementation "joda-time:joda-time:2.2"
testImplementation "junit:junit:4.12"
}
When i make a gradle build and a :
java -jar build\libs\jajson-1.2.1.jar
It works fine and print hello
But when i try to launch the class only with :
java build\classes\java\main\JaJson.class
I have a :
Impossible to found or load main class for build\classes\java\main\JaJson.class
And before each build i rm the builds folder.
rd /s /q build
gradle build && java -jar build\libs\jajson-1.2.1.jar && java build\classes\java\main\JaJson.class
regards

Run as
java -cp build/classes/main/java JaJason
As explained in the Java command's help you need to give the name of the main class, not a path to the main class. If your classes don't live in the current directory (or in their package directory right under the current directory), you need to specify the classpath:
--class-path classpath, -classpath classpath, or -cp classpath
[...] If the class path option isn't used and classpath isn't set, then the user class path consists of the current directory (.).
That said, you can also run a simple .java file straight from the command line:
java src/JaJson.java
This is useful to quickly run single-file programs without going through the whole Gradle build cycle.

Related

Gradle 7.x fat executable jar displays Error: Could not find or load main class

I have spent 3 days trying to see why this error is produced when executing the jar.
Finally, I opened the jar file and noticed that the META-INF folder contains the MANIFEST.MF file but also some folders and some other files too.
If I delete all the files except the MANIFEST.MF file (the folders are not deleted) then the error disappears and I can execute the jar.
The build.gradle file I have used is:
plugins {
// Apply the java-library plugin for API and implementation separation.
id 'java-library'
id 'java'
id 'application'
id 'eclipse' // for avoiding 'java.smartcardio' complain #see:https://stackoverflow.com/a/75222235/7704658
}
// This code is for avoiding 'java.smartcardio' complain in Eclipse #see: https://stackoverflow.com/a/75222235/7704658
eclipse {
classpath {
file {
whenMerged {
def jre = entries.find { it.path.contains 'org.eclipse.jdt.launching.JRE_CONTAINER' }
jre.entryAttributes['module'] = 'true'
jre.entryAttributes['limit-modules'] = 'java.se,jdk.accessibility,jdk.dynalink,jdk.httpserver,jdk.jartool,jdk.javadoc,jdk.jconsole,jdk.jshell,jdk.jsobject,jdk.management.jfr,jdk.net,jdk.nio.mapmode,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.unsupported.desktop,jdk.xml.dom,java.smartcardio'
jre.entryAttributes['add-modules'] = 'java.smartcardio' //--limit-modules java.se --add-modules java.smartcardio
}
}
}
}
repositories {
jcenter()
mavenCentral()
maven { url "https://jitpack.io" } //#see: https://stackoverflow.com/questions/38905939/how-to-import-library-from-jitpack-io-using-gradle
flatDir {dirs "$rootDir/../mynewtargets2"} //#see https://stackoverflow.com/a/25966303
}
// My customization
project.jar.destinationDirectory = file("$rootDir/../mynewtargets2")
project.archivesBaseName = 'd05-autofirma-simple'
project.version = '4.0'
dependencies {
api libs.pdfbox
/** other apis stuff go here.........*/
}
distTar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
distZip {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
application {
mainClass = 'es.gob.afirma.standalone.SimpleAfirma'
}
jar {
zip64=true
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes(
'Main-Class': 'es.gob.afirma.standalone.SimpleAfirma',
)
}
archiveClassifier = "all"
from {
sourceSets.main.allSource //Include java sources
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Can anybody explain why the MANIFEST.MF cannot share the META-INF folder with any other file?
Thanks

Loading CSS in Java with JavaFX works in IntelliJ but not in jar built by Gradle

I'm having some trouble getting my code, which uses JavaFX, to run in a jar file. It runs fine in Intellij, but when I try to run the jar file I get:
Exception in Application start method caused by java.lang.NullPointerException
The line in question is: loginScene.getStylesheets().add(LoginUI.class.getResource("UI.css").toExternalForm());
I'm using Gradle to build my jar so I think my problem is caused by my compiled code not including the UI.css file. My css file is currently located in the same directory as my LoginUI class.
My build.gradle file looks like this:
apply plugin: 'java'
sourceCompatibility = 1.11
repositories {
mavenCentral()
}
def currentOS = org.gradle.internal.os.OperatingSystem.current()
def platform
if (currentOS.isWindows()) {
platform = 'win'
} else if (currentOS.isLinux()) {
platform = 'linux'
} else if (currentOS.isMacOsX()) {
platform = 'mac'
}
dependencies {
compile "org.openjfx:javafx-base:11:${platform}"
compile "org.openjfx:javafx-graphics:11:${platform}"
compile "org.openjfx:javafx-controls:11:${platform}"
compile "org.openjfx:javafx-fxml:11:${platform}"
compile "com.google.code.gson:gson:2.2.4"
compile "org.apache.commons:commons-lang3:3.6"
compile "org.apache.httpcomponents:httpclient:4.5.6"
}
task run(type: JavaExec) {
classpath sourceSets.main.runtimeClasspath
main = "project.Main"
}
sourceSets {
main {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.css"]
}
}
}
jar {
manifest {
attributes 'Main-Class': 'main.java.edu.ufl.activitymonitor.Main'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
compileJava {
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml'
]
}
}
run {
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml'
]
}
}
So far I have tried:
1. Adding the following to my build.gradle file (like in this solution):
sourceSets {
main {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.css"]
}
}
}
Moving my css files from main/java. to main/resources so my file structure looks like this:
directory structure
And then replacing "UI.css" with either: "../../../../resources/UI.css", "../../../resources/UI.css", "../../../../../resources/UI.css", or "/UI.css", or just leaving it as UI.css. However, this just results in a nullpointer error in IntelliJ.
How do I fix this?
UPDATE: I also added the last two lines to my build.gradle (from this question) and it didn't work:
jar {
manifest {
attributes 'Main-Class': 'main.java.edu.ufl.activitymonitor.Main'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
from('src/main/java') {
include '**/*.css'
}
}
Update: Since I don't have a lot of time before deploying my code for an experiment, I ended up using inline css for the most important graphical elements. It's not perfect, but it does work and it is enough for my purposes.

How to add static files to jar using Gradle build in Spring Boot + Angular 2 project

I have a Spring Boot + Angular 2 project. I want to deploy it to Heroku.
I'm able to run the npm build then copy the generated files over to the public folder (src/resources/public) manually, then run the backend build.
What I want to do is to set up a gradle build that will do all of that at once.
What I have so far is a gradle build that will build the front end, build the backend, however it does not copy the static files before generating the jar. Since the jar does not contain said static files, it won't work on Heroku.
Here's the project folder structure:
root
backend
src/main/java
src/main/resources
frontend
--> angular files go here
build/libs -> where the JAR file goes
The gradle build file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
// spring
classpath('org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE')
classpath('org.springframework:springloaded:1.2.6.RELEASE')
}
}
plugins {
id "com.moowork.node" version "1.2.0"
}
// gradle wrapper
task wrapper(type: Wrapper) {
gradleVersion = '3.4'
}
// configure gradle-node-plugin
node {
version = '8.1.4'
npmVersion = '5.0.3'
download = true
workDir = file("${project.projectDir}/node")
nodeModulesDir = file("${project.projectDir}/")
}
// clean node/node_modules/dist
task npmClean(type: Delete) {
final def webDir = "${rootDir}/frontend"
delete "${webDir}/node"
delete "${webDir}/node_modules"
delete "${webDir}/dist"
delete "${webDir}/coverage"
delete "${rootDir}/backend/src/main/resources/public"
}
// clean task for npm
task copyFiles {
doLast {
copy {
from "${rootDir}/frontend/dist"
into "${rootDir}/backend/src/main/resources/public"
}
}
}
// build task for npm
task frontendBuild {}
frontendBuild.dependsOn(npm_install)
frontendBuild.dependsOn(npm_run_build)
npm_install {
args = ['--prefix', './frontend']
}
npm_run_build {
args = ['--prefix', './frontend']
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
sourceSets {
main {
java {
srcDirs = ['backend/src/main/java']
}
resources {
srcDirs = ['backend/src/main/resources']
}
}
}
copyFiles.dependsOn(frontendBuild);
compileJava.dependsOn(frontendBuild);
task backendBuild {}
backendBuild.dependsOn(compileJava)
backendBuild.dependsOn(jar)
jar.dependsOn(copyFiles)
repositories {
mavenCentral()
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8')
}
}
idea {
module {
inheritOutputDirs = false
outputDir = file("${buildDir}/classes/main/")
}
}
jar {
baseName = 'expense-splitter'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
configurations {
dev
}
dependencies {
// spring
compile('org.springframework.boot:spring-boot-starter-web:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-data-jpa:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-security:1.5.2.RELEASE')
compile('org.apache.commons:commons-lang3:3.3.2')
// to make hibernate handle java 8 date and time types correctly
// it's marked as deprecated but we need to keep it until
// spring boot jpa starts using hibernate 5.2
compile('org.hibernate:hibernate-java8:5.1.0.Final')
// json web tokens
compile ('io.jsonwebtoken:jjwt:0.7.0')
compile 'mysql:mysql-connector-java'
// google gson
compile('com.google.code.gson:gson:2.8.0')
// jackson - parsing of java 8 date and time types
compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.7')
// spring dev tools
dev('org.springframework.boot:spring-boot-devtools:1.5.2.RELEASE')
// testing
testCompile('org.springframework.boot:spring-boot-starter-test:1.5.2.RELEASE')
}
// run spring boot app
bootRun {
//addResources = true
classpath = sourceSets.main.runtimeClasspath + configurations.dev
jvmArgs = ["-Xdebug -agentlib:jdwp=transport=dt_socket,address=8080,server=y,suspend=n"]
}
// run all task
task runAll {}
runAll.dependsOn(bootRun)
Thanks in advance,
Try a different approach. Instead of manually copying the resources, tell Gradle that when it processes resources for the JAR, also take into consideration what is in frontend/dist/:
processResources {
from ('frontend/dist/') {
into 'public'
}
}
This should result in a JAR containing a public/ directory, with the contents of frontend/dist/ inside of it.
Gradle configuration for Spring Boot 1.5\2.x + Angular 2-6
Angular in sub-folder frontend
Frontend module
Crate build.gradle:
plugins {
id "com.moowork.node" version "1.2.0"
}
node {
version = '8.11.3'
npmVersion = '5.6.0'
download = true
workDir = file("${project.buildDir}/node")
nodeModulesDir = file("${project.projectDir}")
}
task build(type: NpmTask) {
args = ['run', 'build']
}
build.dependsOn(npm_install)
Note for Angular 6
Update outputPath value in angular.json to 'dist'
Backend module
Edit build.gradle for backend module:
Spring Boot 2.X:
bootJar {
archiveName = "yourapp.jar"
mainClassName = 'com.company.app.Application'
from('frontend/dist') {
into 'static'
}
}
Spring Boot 1.5.X:
jar {
archiveName = "yourapp.jar"
manifest {
attributes 'Main-Class': 'com.company.app.Application'
}
from('frontend/dist') {
into 'static'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Finally execute bootRepackage or bootJar task and check results in builds/libs
Assume that front end is located at the following folder: src/main/webapp/fe-ui/, the following solution for the Spring Boot version 2.1.1.RELEASE could be considered:
bootJar {
baseName = 'jar-name'
version = '0.1.0'
from('src/main/webapp/fe-ui/build') {
into 'public'
}
}
task installFeDependencies(type: NpmTask) {
args = ['install']
}
task buildFe(type: NpmTask) {
args = ['run', 'build']
dependsOn installFeDependencies
}
compileJava {
dependsOn buildFe
}
Running gradlew build will install, build front end as well as will invoke bootJar. The latter will package built front end bundle.

Gradle application plugin with multiple main classes

I'm using the gradle 'application' plugin to start my application. This works well.
Now I want to add the option to start a different main class in the same project. Can I change the plugin's configuration to allow that?
apply plugin: 'application'
mainClassName = "net.worcade.my.MainClass"
From http://mrhaki.blogspot.com/2010/09/gradle-goodness-run-java-application.html
apply plugin: 'java'
task(runSimple, dependsOn: 'classes', type: JavaExec) {
main = 'com.mrhaki.java.Simple'
classpath = sourceSets.main.runtimeClasspath
args 'mrhaki'
systemProperty 'simple.message', 'Hello '
}
Clearly then what you can change:
runSimple can be named whatever you want
set main as appropriate
clear out args and systemProperty if not needed
To run:
gradle runSimple
You can put as many of these as you like into your build.gradle file.
You can directly configure the Application Plugin with properties:
application {
mainClassName = project.findProperty("chooseMain").toString()
}
And after in command line you can pass the name of the main class:
./gradlew run -PchooseMain=net.worcade.my.MainClass
Here's how you can generate multiple start scripts if you need to package your apps
application {
applicationName = "myapp"
mainClassName = "my.Main1"
}
tasks.named<CreateStartScripts>("startScripts") {
applicationName = "myapp-main1"
}
val main2StartScripts by tasks.register("main2StartScripts", CreateStartScripts::class) {
applicationName = "myapp-main2"
outputDir = file("build/scripts") // By putting these scripts here, they will be picked up automatically by the installDist task
mainClassName = "my.Main2"
classpath = project.tasks.getAt(JavaPlugin.JAR_TASK_NAME).outputs.files.plus(project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)) // I took this from ApplicationPlugin.java:129
}
tasks.named("installDist") {
dependsOn(main2StartScripts)
}
Use javaExec task to handle it :
task run(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
if (project.hasProperty('first')){
if (chooseMain == 'Main1'){
main = 'application.Main1'
} else if (chooseMain == 'second'){
main = 'application.Main2'
}
} else {
println 'please pass the main name'
}
}
And from the command line pass your option in that way :
gradle run -PchooseMain=first

Gradle compile project manifest empty

I have a probleme with my build.gradle, it's compile fine but when i try to execute the .jar the console give me this: "no manifest manifest attribute..."
it's my bluid.gradle:
apply plugin: 'java'
group = "com.xxx.xxx.xxx"
archivesBaseName = "xxx"
version = "0.1"
task pack(type: Jar, dependsOn: 'jar') {
inputs.files jar.archivePath;
jar {
baseName = 'xxxx'
version = '0.1'
}
manifest {
attributes(
"Manifest-Version" : "1.0",
"Main-Class" : "com.xxx.xxx.xxx.xxx"
)
}
doLast {
manifest.writeTo("${buildDir}/MANIFEST.MF")
project.ant {
taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask", classpath: configurations.tools.asPath
jarjar(jarfile: archivePath, manifest: "${buildDir}/MANIFEST.MF") {
fileset(dir : "${buildDir}/classes")
fileset(dir : "${buildDir}/resources/main")
configurations.runtime.files.each { jarjarFile ->
zipfileset(src: jarjarFile) {
// WARNING: MUST keep META-INF/DgmInfo, META-INF/services, ... which are needed by Groovy
}
}
rule pattern: "*", result: "#0"
}
}
}
configurations {
tools
}
dependencies {
tools files("${rootDir}/tools/jarjar-1.4.jar")
compile files("${rootDir}/lib/bluecove-2.1.0.jar")
compile files("${rootDir}/lib/bluecove-gpl-2.1.0.jar")
}
}
I don't write the whole code, I don't really know to code a gradle script,
someone help ? :)
I understand that this part:
"Main-Class" : "com.xxx.xxx.xxx.xxx"
in reality is pointing to a valid Java class that has a main method inside, and the class is on your class path?
If yes, unzip your output jar, find META-INF folder and check what is inside MANIFEST.MF and tell us.

Categories