Gradle builds a jar without classes - java

build.gradle:
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = '1.0'
jar {
manifest {
attributes 'Main-Class': 'app.Main'
}
}
repositories {
mavenCentral()
}
dependencies {
}
Main.java:
package app;
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
I need to build a jar, so I could run it from command line
java -Xms6000m -Xmx7100m -jar sample.jar
My project is more complex than "Hello World", the problem I am trying to solve is that my jar has only MANIFEST file
Manifest-Version: 1.0
Main-Class: app.Main
I created my project in Eclipse IDE with buildship plugin. (I do not think there is a problem)
I build my project in command line.
gradlew clean build
Command line output
C:\Development\Workspaces\training\sample>gradlew clean build
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
C:\Development\Workspaces\training\memoryAllocation2>
My project structure.

Your source files are not matching your build script. You either have to put your files in the conventional src/main/java/ directory, or change your build script to tell Gradle where to find the source files.

To summarize the various comments into one complete answer:
Gradle uses, just like Maven, a approach called convention over configuration. This also includes a convention for the location of source files. Without any configuration, Gradle expects the source files for your application under src/main/java. Test sources can be placed under src/test/java.

Related

Gradle not compiling dependency jars in lib folder

I am new to gradle and learning now. I am trying to build a runnable jar using gradle(My builded jar should be run from command prompt). I just started with a simple HelloWorld project with a dependency and try to build it using gradle. I am not using maven. So I added the dependency jar to the lib folder inside project folder. Below are the details.
Gradle Version: 3.1
Eclipse Version: Neon
HelloWorld.java
package com.padhu.test;
import org.joda.time.LocalTime;
public class HelloWorld {
public static void main(String[] args) {
// TODO Auto-generated method stub
LocalTime currentTime = new LocalTime();
System.out.println("The current local time is: " + currentTime);
System.out.println("Hello World");
}
}
Project structure:
project_structure
build_path_snap
build_path_details
build.gradle file:
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'com.padhu.test.HelloWorld'
repositories {
flatDir {
dirs 'lib'
}
}
dependencies {
compile files(fileTree(dir: 'lib', includes: ['*.jar']))
}
jar {
manifest {
attributes(
'Main-Class': 'com.padhu.test.HelloWorld'
)
}
}
I can successfully execute gradle build in my cmd and jar file is getting generated. But inside jar file, I can see only HelloWorld folder structure, but couldnt see the dependency files. So I am not able to run the jar from command prompt since I am getting NoClassDefFoundError: org/joda/time/LocalTime..
I tried fixing the issue myself by searching and reading blogs..but I am not able to run the jar successfully.
Kindly help me.
It seems, you misunderstand, how does application plugin behave. It doesn't make a so-called fat-jar, which includes all it's dependencies, rather creates a jar and able to run it, adding all the dependencies to the classpath.
You can run your application as follows:
gradle run
Or you can use the automatically applied distribution plugin and create a distribution of your project with scripts to start it and all the dependent libraries in separate folder. Just run it as:
gradle distZip
You can read more about it in the official user guide.

gradle classes are not generated

I am trying to convert my project to gradle and unable to get the class files generated under build folder. Here is the build.gradle file:
import org.gradle.internal.os.OperatingSystem;
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceSets {
main {
java {
srcDirs = ["abc/def/"]
include('include/Constants.java')
}
}
}
task initial(type: Exec) {
doFirst {
println 'Started compiling constants'
}
if(OperatingSystem.current().isWindows()) {
println 'Compiling on windows'
//Run some bash script here
}
else {
print 'Compiling on unix'
//Run some shell script here
}
doLast {
println 'Finish compiling constants'
}
}
jar {
baseName = 'output'
}
dependencies {
compile files('../lib/log4j/log4j.jar')
compile files('../lib/findbugs/findbugs.jar')
compile files('../lib/guava/guava-19.0.jar')
}
When i do gradle build, it says successfull, but see no classes generated under build folder.
Any help?
Fixed it after some debugging. The issue was the include after the srcDirs did not work as the path was one level higher than the path defined in srcDirs.
I had a similar issue the other day, it was not generating the compiled classes when I run the build on IntelliJ or even on the terminal.
After trying a lot of things what solved the issue was deleting the .gradle directory and running again a ./gradlew clean build.
It was a weird one, but I hope it might help to someone having the same issue.

intellij build jar artifact containing gradle dependencies

I basically want to do something simple - or atleast i think it should be pretty simple.
My goal is to create an Intellij gradle project, add some dependencies to the module using gradle and add some java source code to it.
Then I just want to have an option to somehow compile the whole thing into 1 jar, containing all grade dependencies and being able to execute using "java -jar"
However it turned out that this is not as easy is i had thought.
I just created a new gradle project from intellij and added a Main class.
I´ll give you an overview over my files:
settings.gradle:
rootProject.name = 'gradleTestNewJar'
build.gradle:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
sourceCompatibility = 1.6
version = '1.0'
repositories {
mavenCentral()
}
mainClassName = "com.randomPackage.StarterClass"
dependencies {
compile 'org.seleniumhq.selenium:selenium-java:2.46.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
main class:
package com.randomPackage;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class StarterClass {
public static void main(String[] args){
System.out.println("test");
WebDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_38);
driver.quit();
}
}
The main method of "MyStart" is executed when running from Intellij via debug.
So it works, when all dependencies get loaded correctly.
NOTE: I use Intellij Community Edition if this makes any difference.
What i tried:
1. I tried to just use "gradlew clean build".
This created a jar, but without libs.
But I didn´t expect it to be as easy as this.
2. I tried to build an artifact of the module as suggested here:
http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
I tried it with extracted and not extracted dependencies.
In both cases the dependencies were added into the jar, but they were added to the root of the jar.
When i tried to run the jar file via "java -jar", it complained:
"Exception in thread "main" java.lang.NoClassDefFoundError: org/openqa/selenium/WebDriver
..."
OK, so it couldn´t load the dependencies.
NOTE: I thought that the dependencies were not added to the classpath, but i am not sure about this. However, i would expect Intellij to add dependencies to the classpath( or declare in the manifest file)
3. I also tried to use the gradle application plugin.
However this creates a zip/tar which contains a execute script and a bin folder which was not my intention.
So i started googling for hours and hours but i cann´t find a solution to my problem.
Come on this cannot be so hard - it is just so basic.
I am sure some genius can help me out and point me to my - probably stupid - failure.
My current solution is as follows:
I use gradle to build a jar containing all libs, I do this witha custom task called fatJar.
Here is a part from my build.gradle
apply plugin: 'java'
jar {
manifest {
attributes("Manifest-Version": "1.0",
"Main-Class": "com.randomPackage.MainClass");
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
Then I just execute "gradle fatJar" on the command line and get a perfect jar.

Why is class file not generated in JavaCompile task in gradle

I met a problem when I use gradle to build my android project. In my build process,I need to compile a single java file to the class file.My project file structure is app -> build_tools->A.java. And my task of compiling A.java is following:
task compileEncodeUtil(type:JavaCompile) {
println('****************************compileEncodeUtil start*******************')
source = ['build_tools']
include '*.java'
classpath = files('.')
destinationDir=['build_tools']
}
When I run this task , it runs successfully, but in the folder build_tools, there are no class files. Any help would be appreciated.
For the following folder structure:
build.gradle
build-tools/
Lol.java
pkg/
Lol2.java
the following script works perfectly fine:
apply plugin: 'java'
task compileEncodeUtil(type:JavaCompile) {
source = ['build_tools']
include '**/*.java'
classpath = files('.')
destinationDir=['build_tools']
}

Creating runnable JAR with Gradle

Until now I created runnable JAR files via the Eclipse "Export..." functionallity but now I switched to IntelliJ IDEA and Gradle for build automation.
Some articles here suggest the "application" plugin, but this does not entirely lead to the result I expected (just a JAR, no start scripts or anything like this).
How can I achieve the same result Eclipse does with the "Export..." dialog?
An executable jar file is just a jar file containing a Main-Class entry in its manifest. So you just need to configure the jar task in order to add this entry in its manifest:
jar {
manifest {
attributes 'Main-Class': 'com.foo.bar.MainClass'
}
}
You might also need to add classpath entries in the manifest, but that would be done the same way.
See http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
If you already have defined an application context, you can re-use the definition rather than duplicate it:
application {
// Define the main class for the application.
mainClass = 'com.foo.bar.MainClass'
}
jar {
manifest {
attributes 'Main-Class': application.mainClass
}
}
Both JB Nizet and Jorge_B's answers are correct.
In its simplest form, creating an executable JAR with Gradle is just a matter of adding the appropriate entries to the manifest. However, it's much more common to have dependencies that need to be included on the classpath, making this approach tricky in practice.
The application plugin provides an alternate approach; instead of creating an executable JAR, it provides:
a run task to facilitate easily running the application directly from the build
an installDist task that generates a directory structure including the built JAR, all of the JARs that it depends on, and a startup script that pulls it all together into a program you can run
distZip and distTar tasks that create archives containing a complete application distribution (startup scripts and JARs)
A third approach is to create a so-called "fat JAR" which is an executable JAR that includes not only your component's code, but also all of its dependencies. There are a few different plugins that use this approach. I've included links to a few that I'm aware of; I'm sure there are more.
shadow
one-jar
spring-boot
capsule
Least effort solution for me was to make use of the gradle-shadow-plugin
Besides applying the plugin all that needs to be done is:
Configure the jar task to put your Main class into manifest
jar {
manifest {
attributes 'Main-Class': 'com.my.app.Main'
}
}
Run the gradle task
./gradlew shadowJar
Take the app-version-all.jar from build/libs/
And finally execute it via:
java -jar app-version-all.jar
As others have noted, in order for a jar file to be executable, the application's entry point must be set in the Main-Class attribute of the manifest file. If the dependency class files are not collocated, then they need to be set in the Class-Path entry of the manifest file.
I have tried all kinds of plugin combinations and what not for the simple task of creating an executable jar and somehow someway, include the dependencies. All plugins seem to be lacking one way or another, but finally I got it like I wanted. No mysterious scripts, not a million different mini files polluting the build directory, a pretty clean build script file, and above all: not a million foreign third party class files merged into my jar archive.
The following is a copy-paste from here for your convenience..
[How-to] create a distribution zip file with dependency jars in subdirectory /lib and add all dependencies to Class-Path entry in the manifest file:
apply plugin: 'java'
apply plugin: 'java-library-distribution'
repositories {
mavenCentral()
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.3.2'
}
// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)
jar {
// Keep jar clean:
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
manifest {
attributes 'Main-Class': 'com.somepackage.MainClass',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
}
// How-to add class path:
// https://stackoverflow.com/questions/22659463/add-classpath-in-manifest-using-gradle
// https://gist.github.com/simon04/6865179
}
Hosted as a gist here.
The result can be found in build/distributions and the unzipped contents look like this:
lib/commons-lang3-3.3.2.jar
MyJarFile.jar
Contents of MyJarFile.jar#META-INF/MANIFEST.mf:
Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib/commons-lang3-3.3.2.jar
This is for Kotlin DSL (build.gradle.kts).
Method 1 (no need for application or other plugins)
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
// OR another notation
// manifest {
// attributes["Main-Class"] = "com.example.MyMainClass"
// }
}
If you use any external libraries, use below code. Copy library JARs in libs sub-directory of where you put your result JAR. Make sure your library JAR files do not contain space in their file name.
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
manifest.attributes["Class-Path"] = configurations
.runtimeClasspath
.get()
.joinToString(separator = " ") { file ->
"libs/${file.name}"
}
}
Note that Java requires us to use relative URLs for the Class-Path attribute. So, we cannot use the absolute path of Gradle dependencies (which is also prone to being changed and not available on other systems). If you want to use absolute paths, maybe this workaround will work.
Create the JAR with the following command:
./gradlew jar
The result JAR will be created in build/libs/ directory by default.
Method 2: Embedding libraries (if any) in the result JAR (fat or uber JAR)
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree) // OR .map { zipTree(it) }
from(dependencies)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Creating the JAR is exactly the same as the previous method.
Method 3: Using the Shadow plugin (to create a fat or uber JAR)
plugins {
id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these will be reflected for Shadow as well
tasks.jar {
manifest.attributes["Main-Class"] = "org.example.MainKt"
}
Create the JAR with this command:
./gradlew shadowJar
See Shadow documentations for more information about configuring the plugin.
Running the created JAR
java -jar my-artifact.jar
The above solutions were tested with:
Java 17
Gradle 7.1 (which uses Kotlin 1.4.31 for .kts build scripts)
See the official Gradle documentation for creating uber (fat) JARs.
For more information about manifests, see Oracle Java Documentation: Working with Manifest files.
Note that your resource files will be included in the JAR file automatically (assuming they were placed in /src/main/resources/ directory or any custom directory set as resources root in the build file). To access a resource file in your application, use this code (note the / at the start of names):
Kotlin
val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText()
// Alternative ways:
// val vegetables = object{}.javaClass.getResource("/vegetables.txt").readText()
// val vegetables = MyClass::class.java.getResourceAsStream("/vegetables.txt").reader().readText()
// val vegetables = object{}.javaClass.getResourceAsStream("/vegetables.txt").reader().readText()
Java
var stream = MyClass.class.getResource("/vegetables.txt").openStream();
// OR var stream = MyClass.class.getResourceAsStream("/vegetables.txt");
var reader = new BufferedReader(new InputStreamReader(stream));
var vegetables = reader.lines().collect(Collectors.joining("\n"));
You can use the SpringBoot plugin:
plugins {
id "org.springframework.boot" version "2.2.2.RELEASE"
}
Create the jar
gradle assemble
And then run it
java -jar build/libs/*.jar
Note: your project does NOT need to be a SpringBoot project to use this plugin.
Have you tried the 'installApp' task? Does it not create a full directory with a set of start scripts?
http://www.gradle.org/docs/current/userguide/application_plugin.html
Thank you Konstantin, it worked like a charm with few nuances. For some reason, specifying main class as part of jar manifest did not quite work and it wanted the mainClassName attribute instead. Here is a snippet from build.gradle that includes everything to make it work:
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
baseName = 'myapp'
}
After running gradle shadowJar you get myapp-{version}-all.jar in your build folder which can be run as java -jar myapp-{version}-all.jar.
You can define a jar artifact in the module settings (or project structure).
Right click the module > Open module settings > Artifacts > + > JAR > from modules with dependencies.
Set the main class.
Making a jar is then as easy as clicking "Build artifact..." from the Build menu. As a bonus, you can package all the dependencies into a single jar.
Tested on IntelliJ IDEA 14 Ultimate.
I checked quite some links for the solution, finally did the below mentioned steps to get it working. I am using Gradle 2.9.
Make the following changes in your build,gradle file :
Mention plugin:
apply plugin: 'eu.appsatori.fatjar'
Provide the Buildscript:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
}
}
Provide the Main Class:
fatJar {
classifier 'fat'
manifest {
attributes 'Main-Class': 'my.project.core.MyMainClass'
}
exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
}
Create the fatjar:
./gradlew clean fatjar
Run the fatjar from /build/libs/ :
java -jar MyFatJar.jar
Here is the solution I tried with Gradle 6.7
Runnable fat Jar (with all dependent libraries copied to the jar)
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.gradle.App'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
}
Runnable jar with all dependencies copied to a directory and adding the classpath to the manifest
def dependsDir = "${buildDir}/libs/dependencies/"
task copyDependencies(type: Copy) {
from configurations.compile
into "${dependsDir}"
}
task createJar(dependsOn: copyDependencies, type: Jar) {
manifest {
attributes('Main-Class': 'com.example.gradle.App',
'Class-Path': configurations.compile.collect { 'dependencies/' + it.getName() }.join(' ')
)
}
with jar
}
How to use ?
Add the above tasks to build.gradle
Execute gradle fatJar //create fatJar
Execute gradle createJar // create jar with dependencies copied.
More details : https://jafarmlp.medium.com/a-simple-java-project-with-gradle-2c323ae0e43d
Configure Main Class to your Manifest
If you are using gradle project, just add the following into your build.gradle
jar {
manifest {
attributes(
'Main-Class': 'pokerhandscorer.PokerHandScorer'
)
}
}
Where 'pokerhandscorer' is the name of the package name,
and PokerHandScorer is the main class name
This creates a jar file into your \build\libs{jarFilename}.jar
Run jar file using java -jar /{path}/{jarFileName.jar}
java -jar /{path}/{jarFileName.jar}

Categories