Spring Boot 2 - Change Jar Name - spring-boot

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

Related

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

Fat Jar expands dependencies with Gradle Kotlin DSL

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")
}
}
}

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

How do I add a .properties file into my WAR using gradle?

WAR
- META-INF
- WEB-INF
- classes
- META-INF
- myApp.properties <-- Needs added
How do I add a .properties file into my WAR using gradle?
The file was later introduced into the project but doesn't
get added?
build.gradle
import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.methods.GetMethod
group = 'gradle'
version = '1.0'
apply plugin: 'war'
apply plugin: 'jetty'
apply plugin: 'eclipse'
eclipseProject
{
projectName = 'crap'
}
defaultTasks 'build'
dependencies
{
//all my dependencies
}
war
{
classpath fileTree('lib')
}
jar.enabled = true
[jettyRun, jettyRunWar]*.daemon = true
stopKey = 'stoppit'
stopPort = 9451
httpPort = 8080
scanIntervalSeconds = 1
war {
from('<path-to-props-file>') {
include 'myApp.properties'
into('<target-path>')
}
}
Something like this should work:
war {
from('<path-to-props-file>') {
include 'myApp.properties'
}
}
If you want to specify which directory you want the properties file to be located in:
war {
from('<path-to-props-file>') {
include 'myApp.properties'
into('<targetDir>')
}
}
eg1:
war {
webInf{
from('PATH_TO_SOURCE_FOLDER') {
include 'FILE_TO_BE_INCLUDED'
into('TARGET_FOLDER_RELATIVE_TO_WEB_INF_DIR')
}
}
}
eg2:
war {
webInf{
from('src/META-INF') {
include 'persistence.xml'
into('classes/META-INF/')
}
}
}
For more information check the online documentation: Chapter 26. The War Plugin
I normally use an environments folder from which I pick a given configuration file based on the deploy variable. Ex.:
from("environments/system.${env}.properties"){
include "system.${env}.properties"
into 'WEB-INF'
rename("system.${env}.properties", 'system.properties')
}
the property is passed through gradle as:
./gradlew buildDocker -Penv=prod

Using Gradle to build a JAR with dependencies

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 this 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.
I posted a solution in JIRA against Gradle:
// Include dependent libraries in archive.
mainClassName = "com.company.application.Main"
jar {
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Note that mainClassName must appear BEFORE jar {.
The answer by #felix almost brought me there. I had two issues:
With Gradle 1.5, the manifest tag was not recognised inside the fatJar task, so the Main-Class attribute could not directly be set
the jar had conflicting external META-INF files.
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
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.
Since use of compile to list dependencies is now deprecated and all should switch to implementation the solution to build a Jar with all dependencies should use the example from this website.
https://docs.gradle.org/current/userguide/working_with_files.html#sec:creating_uber_jar_example
Specifically this command:
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it)
Here is full gradle section:
[1]: https://docs.gradle.org/current/userguide/working_with_files.html#sec:creating_uber_jar_example
task uberJar(type: Jar) {
archiveClassifier = 'uber'
from sourceSets.main.output
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { 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
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) }
}
}
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'
}
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"
}
}
Simple sulution
jar {
manifest {
attributes 'Main-Class': 'cova2.Main'
}
doFirst {
from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
I use next script for Gradle 7.3.3. It resolves errors and exceptions that I was faced with when I was trying to implement solutions from this question.
jar {
manifest {
attributes(
"Main-Class": "path.to.main.Application",
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
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()
}
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 {
-----
}
}
There is gradle plugin shadow jar with seamless setup.
plugins {
id "com.github.johnrengelman.shadow" version "5.0.0"
}
shadowJar {
mergeServiceFiles()
}
Please check about version compatibilities with your gradle version here:
https://github.com/johnrengelman/shadow#latest-test-compatibility
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) }
}
}
There's something to keep in mind about this type of solution:
task fatJar(type: Jar) {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
It works so long as you're using "compile" dependencies. It doesn't work if you're using "implementation" dependencies.
Try "runtimeClasspath" if "compile" and "implementation" not working.
jar {
manifest {
attributes "Main-Class": "com.example.app"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
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"));
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')
}
}

Resources