Fat Jar expands dependencies with Gradle Kotlin DSL - gradle

I am trying to build a fat jar using the following in my Kotlin based gradle file.
val fatJar = task("fatJar", type = Jar::class) {
baseName = "safescape-lib-${project.name}"
// manifest Main-Class attribute is optional.
// (Used only to provide default main class for executable jar)
from(configurations.runtimeClasspath.map({ if (it.isDirectory) it else zipTree(it) }))
with(tasks["jar"] as CopySpec)
}
tasks {
"build" {
dependsOn(fatJar)
}
}
However, the fat jar has all the dependencies expanded out. I would like to have the jars included as is in a /lib directory but I cannot work out how to achieve this.
Can anyone give any pointers as to how I can achieve this?
Thanks

Well you are using zipTree in that map part of the spec, and it behaves according to the documentation: it unzips the files that are not a directory.
If you want the jars in /lib, replace your from with:
from(configurations.runtimeClasspath) {
into("lib")
}

In case anyone is using kotlin-multiplatform plugin, the configuration is a bit different. Here's a fatJar task configuration assuming JVM application with embedded JS frontend from JS module:
afterEvaluate {
tasks {
create("jar", Jar::class).apply {
dependsOn("jvmMainClasses", "jsJar")
group = "jar"
manifest {
attributes(
mapOf(
"Implementation-Title" to rootProject.name,
"Implementation-Version" to rootProject.version,
"Timestamp" to System.currentTimeMillis(),
"Main-Class" to mainClassName
)
)
}
val dependencies = configurations["jvmRuntimeClasspath"].filter { it.name.endsWith(".jar") } +
project.tasks["jvmJar"].outputs.files +
project.tasks["jsJar"].outputs.files
dependencies.forEach { from(zipTree(it)) }
into("/lib")
}
}
}

Related

How do I build a fat jar (bundle) with Bndtools in a Gradle project?

I am currently trying to create a bundle with bnd in a Gradle project.
The idea was to try getting the list of jar dependencies with Gradle and modify the jar task to add the libs inside the bundle.
Let's say, I would like to remove the includeresource.
-includeresource: lib/jsoup.jar=jsoup-1.14.3.jar
Bundle-ClassPath: ., lib/jsoup.jar
I tried some variations of:
jar {
duplicatesStrategy = 'EXCLUDE'
from {
configurations.runtimeClasspath.findAll {
it.name.endsWith('jar')
}.collect { println it.name; zipTree(it) }
}
}
I can see the name of the jar being printed, but not included inside the bundle, (I know zipTree would expand).
Suggestions from https://discuss.gradle.org/t/how-to-include-dependencies-in-jar/19571/16 do not seem to be valid for bnd, and I suspect bnd overrides the jar task somehow.
A suggestion as:
jar {
def libBuildDir = mkdir "${buildDir}/resources/main/lib"
copy {
from { configurations.jarLibs }
into { libBuildDir }
}
}
Would be perfect, but it does not seem to work for bundles.
Any ideas?

Use gradle to build a jarfile from other jarfiles

I have what should be a simple problem: I have a directory full of jarfiles, and I want to use gradle (v4.4.1) to combine the contents of these jarfiles into a single jarfile (i.e., when I do jar tf big-jar.jar, I want to see a bunch of classes, not a bunch of jars). I tried the following:
task bigJar(type: Jar) {
inputs.dir "$distLibsJar"
outputs.file "$distDir/big-jar.jar"
destinationDir = file("$distDir")
baseName = "big-jar"
from("$distLibsDir")
}
but this produces a jarfile with other jars as its contents rather than the contents of those other jars as the contents of the combined jar.
Any ideas? Thanks...
In this case best way to proceed is with a shadow jar. for this you can have this kind of configuration in build.gradle .posting some sample
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
zip64 true
//classifier "shadow" can be mentioned according to need
mergeServiceFiles()
artifacts {
shadow(tasks.shadowJar.archivePath) {
builtBy shadowJar
}
}
}
artifacts {
archives shadowJar
}
distZip {
dependsOn shadowJar
//appendix='software'
eachFile { file ->
String path = file.relativePath
file.setPath(path.substring(path.indexOf("/")+1,path.length()))
}
doLast{
//operation to perform
}
}
distributions {
main {
contents {
//from and to can be mentioned here
}
}
}
hope it helps

Spring Boot 2 - Change Jar Name

I am using Spring Boot 2 in my Gradle project to do a build to jar in Jenkins, and I would like to change the name of that jar file.
By default, Spring Boot 2 used the Gradle property rootProject.name, which can be set in the /settings.gradle file.
However, I would like to change the jar file name, without changing the rootProject.name.
Here are my bootJar and springBoot sections of the build.gradle file:
bootJar {
launchScript()
}
.
springBoot {
buildInfo {
properties {
artifact = "jarName"
group = "groupName"
name = "projectName"
version = "1.0"
}
}
}
Note: artifact is not setting the jar name, as I expected it to, after reading: https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#integrating-with-actuator
archiveFileName is the new hotness. Everything else is deprecated.
bootJar {
archiveFileName = "${archiveBaseName.get()}.${archiveExtension.get()}"
}
or the Kotlin DSL equivalent:
tasks.getByName<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") {
this.archiveFileName.set("${archiveBaseName.get()}.${archiveExtension.get()}")
}
See:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveName
https://docs.gradle.org/current/userguide/lazy_configuration.html
Since bootJar tasks extends Jar you can use archiveName to set name the directly:
bootJar {
archiveName = 'whatever'
}
Have a look here.
Thanks to #AndyWilkinson for the answer!
bootJar {
baseName "jarName"
launchScript()
}
.
springBoot {
buildInfo {
properties {
group = "groupName"
name = "projectName"
version = "1.0"
}
}
}
For Gradle 6
bootJar {
archiveBaseName = 'freeway-server'
archiveVersion = '1.0.0'
archiveFileName = 'freeway-server.jar'
}
For get:-
System.out.print(bootJar.getArchiveBaseName().get())
System.out.print(bootJar.getArchiveVersion().get())
System.out.print(bootJar.getArchiveFileName().get())
My goal was to remove version from the archive name. I did it this way:
bootJar {
archiveName = "$baseName.$extension"
}
Now Gradle generates "project-name.jar" instead of "project-name-1.0-SNAPSHOT.jar". This solution is general and doesn't hardcode any particular archive name.
You can also use:
tasks.bootJar {
archiveFileName.set("app.jar")
}
Or with the jar-plugin
tasks.jar {
archiveFileName.set("app.jar")
}
Most people simply want to not have the version in the jar name, not change the name completely.
tasks.withType<org.springframework.boot.gradle.tasks.bundling.BootJar> {
archiveVersion.set("")
}
will do it using Kotlin DSL. The final name is given by tasks.bootJar.get().archiveFileName.get().
For me worked
project(':org.awseome.subproject') {
jar() {
archiveFileName = 'nameOfJar.jar'
}
}
inside of main build.gradle. Used
Gradle 6.X
Spring Boot 2.X

Using testCompile output from other subproject (Gradle Kotlin DSL)

I have some utility files in the test sources in one of my gradle subproject and would like to use them in an other subproject.
My "source" subproject is called core, while the one uses it is called tem.
I try to migrate and integrate the following example:
In your Server project:
configurations {
testArtifacts.extendsFrom testCompile
}
task testJar(type: Jar) {
classifier "test"
from sourceSets.test.output
}
artifacts {
testArtifacts testJar
}
In your ServerWeb project:
testCompile project(path: ":Server", configuration: 'testArtifacts')
As far as I get is making the conversation. I added the following to my core.gradle.kts:
val testConfig = configurations.create("testArtifacts") {
extendsFrom(configurations["testCompile"])
}
tasks.register("testJar", Jar::class.java) {
classifier += "test"
from(sourceSets["test"].output)
}
artifacts {
add("testArtifacts", tasks.named<Jar>("testJar") )
}
And tried to refer to it in tem.gradle.kts:
testImplementation(project(":core", "testArtifacts"))
It compiles, but I still can't access the classes from core.
Where did I miss something?
Most of your code should be OK
But you must define classesDirs for jar
tasks.register<Jar>("testJar") {
dependsOn("testClasses")
archiveBaseName.set("${project.name}-test")
from(sourceSets["test"].output.classesDirs)
}
I also added depends on testClasses to be sure that classes are compiled.
You can test that jar is OK by executing testJar task. Then verify that generated jar contains your classes. If you make mistake with from method call then you get empty jar.
The following configuration worked for me to include both the test classes and test resources:
core build.gradle.kts
val testConfig = configurations.create("testArtifacts") {
extendsFrom(configurations["testCompile"])
}
tasks.register("testJar", Jar::class.java) {
dependsOn("testClasses")
classifier += "test"
from(sourceSets["test"].output)
}
artifacts {
add("testArtifacts", tasks.named<Jar>("testJar") )
}
tem build.gradle.kts
testImplementation(project(":core", "testArtifacts"))

Gradle compileKotlin includeRuntime not adding runtime to jar

I have a Kotlin Gradle project, and I would like to include Kotlin's runtime and stdlib in the jar file. I'm currently using this, but it's not including the runtime or stdlib when I build the project using the build.gradle configuration.
compileKotlin {
kotlinOptions {
includeRuntime = true
noStdlib = false
}
}
This is the Gradle code I'm using to include the runtime/stdlib in the jar, but it isn't working like I expect it to. Here's the full build.gradle file for some context:
https://github.com/BenWoodworth/CrossPlatformGreeter/blob/bd1da79f36e70e3d88ed871bc35502ecc3a852fb/build.gradle#L35-L43
Kotlin's Gradle documentation seems to indicate that setting kotlinOptions.includeRuntime to true should include the Kotlin runtime in the resulting .jar.
https://kotlinlang.org/docs/reference/using-gradle.html#attributes-specific-for-kotlin
Edit:
This might be related. When I run compileKotlin, I'm getting a couple of warnings related to the runtime:
:compileKotlin
w: Classpath entry points to a non-existent location: <no_path>\lib\kotlin-runtime.jar
BUILD SUCCESSFUL
Here's an alternative I came up with. It'll add the Kotlin runtime and stdlib to the jar using the jar task.
jar {
from {
String[] include = [
"kotlin-runtime-${version_kotlin}.jar",
"kotlin-stdlib-${version_kotlin}.jar"
]
configurations.compile
.findAll { include.contains(it.name) }
.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Gradle Kotlin DSL:
tasks.withType<Jar> {
val include = setOf("kotlin-stdlib-1.4.0.jar")
configurations.runtimeClasspath.get()
.filter { it.name in include }
.map { zipTree(it) }
.also { from(it) }
}
Try this:
Build script
Unpack jar
Add kotlin runtime and rapack it
type gradle packJar to create jar with kotlin runtime in it
or
type gradle runJar to create and run the jar file
build Script

Resources