I have a multiproject build and I put a task to build a fat jar in one of the subprojects. I created the task similar to the one described in the cookbook.
jar {
from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
manifest { attributes 'Main-Class': 'com.benmccann.gradle.test.WebServer' }
}
Running it results in the following error:
Cause: You can't change a configuration which is not in unresolved state!
I'm not sure what this error means. I also reported this on the Gradle JIRA in case it is a bug.
Excluding unwanted Manifest entries fixed the MainClass file not found error in a Gradle build jar file.
jar{
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
from {
-----
}
}
For those who need to build more than one jar from the project.
Create a function in gradle:
void jarFactory(Jar jarTask, jarName, mainClass) {
jarTask.doFirst {
println 'Build jar ' + jarTask.name + + ' started'
}
jarTask.manifest {
attributes(
'Main-Class': mainClass
)
}
jarTask.classifier = 'all'
jarTask.baseName = jarName
jarTask.from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
{
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
jarTask.with jar
jarTask.doFirst {
println 'Build jar ' + jarTask.name + ' ended'
}
}
then call:
task makeMyJar(type: Jar) {
jarFactory(it, 'MyJar', 'org.company.MainClass')
}
Works on gradle 5.
Jar will be placed at ./build/libs
.
I use task shadowJar
by plugin .
com.github.jengelman.gradle.plugins:shadow:5.2.0
Usage just run ./gradlew app::shadowJar
result file will be at MyProject/app/build/libs/shadow.jar
top level build.gradle
file :
apply plugin: 'kotlin'
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
}
}
app module level build.gradle
file
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
sourceCompatibility = 1.8
kapt {
generateStubs = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"
shadow "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"
implementation project(":module_remote")
shadow project(":module_remote")
}
jar {
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
manifest {
attributes(
'Main-Class': 'com.github.kolyall.TheApplication',
'Class-Path': configurations.compile.files.collect { "lib/$it.name" }.join(' ')
)
}
}
shadowJar {
baseName = 'shadow'
classifier = ''
archiveVersion = ''
mainClassName = 'com.github.kolyall.TheApplication'
mergeServiceFiles()
}
If you want the jar
task to behave normally and also have an additional fatJar
task, use the following:
task fatJar(type: Jar) {
classifier = 'all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
The important part is with jar
. Without it, the classes of this project are not included.
To generate a fat JAR with a main executable class, avoiding problems with signed JARs, I suggest gradle-one-jar plugin. A simple plugin that uses the One-JAR project.
Easy to use:
apply plugin: 'gradle-one-jar'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.github.rholder:gradle-one-jar:1.0.4'
}
}
task myjar(type: OneJar) {
mainClass = 'com.benmccann.gradle.test.WebServer'
}
The answer by @felix almost brought me there. I had two issues:
The following setup resolves this
jar {
manifest {
attributes(
'Main-Class': 'my.project.main',
)
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
To add this to the standard assemble or build task, add:
artifacts {
archives fatJar
}
Edit: thanks to @mjaggard: in recent versions of Gradle, change configurations.runtime
to configurations.runtimeClasspath
Simple sulution
jar {
manifest {
attributes 'Main-Class': 'cova2.Main'
}
doFirst {
from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
This works fine for me.
My Main class:
package com.curso.online.gradle;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = Logger.getLogger(Main.class);
logger.debug("Starting demo");
String s = "Some Value";
if (!StringUtils.isEmpty(s)) {
System.out.println("Welcome ");
}
logger.debug("End of demo");
}
}
And it is the content of my file build.gradle:
apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
compile 'org.apache.commons:commons-lang3:3.0'
compile 'log4j:log4j:1.2.16'
}
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.curso.online.gradle.Main'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
And I write the following in my console:
java -jar ProyectoEclipseTest-all.jar
And the output is great:
log4j:WARN No appenders could be found for logger (com.curso.online.gradle.Main)
.
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more in
fo.
Welcome
Gradle 6.3, Java library. The code from "jar task" adds the dependencies to the "build/libs/xyz.jar" when running "gradle build" task.
plugins {
id 'java-library'
}
jar {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
If you're used to ant then you could try the same with Gradle too:
task bundlemyjava{
ant.jar(destfile: "build/cookmyjar.jar"){
fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
}
}
The answer from @ben almost works for me except that my dependencies are too big and I got the following error
Execution failed for task ':jar'.
> archive contains more than 65535 entries.
To build this archive, please enable the zip64 extension.
To fix this problem, I have to use the following code
mainClassName = "com.company.application.Main"
jar {
manifest {
attributes "Main-Class": "$mainClassName"
}
zip64 = true
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Based on the proposed solution by @blootsvoets, I edited my jar target this way :
jar {
manifest {
attributes('Main-Class': 'eu.tib.sre.Main')
}
// Include the classpath from the dependencies
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
// This help solve the issue with jar lunch
{
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
}
Source: Stackoverflow.com