How do I create an executable fat jar with Gradle with implementation dependencies
I've got a simple project in Gradle 4.6 and would like to make an executable JAR of it. I've tried shadow
, gradle-fatjar-plugin
, gradle-one-jar
, spring-boot-gradle-plugin
plugins but neither of them adds my dependencies declared as implementation
(I don't have any compile
ones). It works with compile
e.g. for gradle-one-jar
plugin but I would like to have implementation
dependencies.
Solution 1:
You can use the following code.
jar {
manifest {
attributes(
'Main-Class': 'com.package.YourClass'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Be sure to replace com.package.YourClass
with the fully qualified class name containing static void main( String args[] )
.
This will pack the runtime dependencies. Check the docs if you need more info.
Solution 2:
Based on the accepted answer, I needed to add one more line of code:
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.yourpackage.Main'
}
archiveClassifier = "all"
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
}
Without this additional line, it omitted my source files and only added the dependencies:
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
For newer gradle (7+), you may see this error:
Execution failed for task ':fatJar'.
> Entry [some entry here] is a duplicate but no duplicate handling strategy has been set. Please
refer to https://docs.gradle.org/7.1/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy
for details.
If this happens add a duplicatesStrategy
such as duplicatesStrategy "exclude"
to the fatJar
task.
And likewise, for Gradle 7+, you have to just remove the configuration.compile.collect
line because it is no longer a valid configuration in this version of gradle.
Solution 3:
The same task can be achieved using Gradle Kotlin DSL in a similar way:
val jar by tasks.getting(Jar::class) {
manifest {
attributes["Main-Class"] = "com.package.YourClass"
}
from(configurations
.runtime
// .get() // uncomment this on Gradle 6+
// .files
.map { if (it.isDirectory) it else zipTree(it) })
}
Solution 4:
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
This line is essential to me.
Solution 5:
Kotlin 1.3.72 & JVM plugin, Gradle 6.5.1
Syntax is changing quickly in all these platforms
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
val main = sourceSets.main.get()
//TODO
register<Jar>("buildFatJar") {
group = "app-backend"
dependsOn(build)
// shouldRunAfter(parent!!.tasks["prepCopyJsBundleToKtor"]) -> This is for incorporating KotlinJS gradle subproject resulting js file.
manifest {
attributes["Main-Class"] = "com.app.app.BackendAppKt"
}
from(configurations.compileClasspath.get().files.map { if (it.isDirectory) it else zipTree(it) })
with(jar.get() as CopySpec)
archiveBaseName.set("${project.name}-fat")
}
}