My project is spring boot with gradle. My goal is to have spring boot generate 2 different boot jars. The first jar is the typical jar created today which would be used in production systems. The second jar would be used by other systems for integration testing. The second jar would have a different set of configuration and dependencies. Has anyone else done this? I did not see any simple configuration for the bootJar
task nor was i successful trying to create my own task based on bootJar
.
UPDATE: Below is the solution which worked based upon Francisco Mateo's answer.
configurations {
integrationImplementation.extendsFrom implementation
integrationRuntimeOnly.extendsFrom runtimeOnly
//...
}
dependencies {
// ...
integrationRuntimeOnly 'com.h2database:h2'
// ...
}
sourceSets {
integration {
compileClasspath = sourceSets.main.output
runtimeClasspath = sourceSets.main.output
}
}
tasks.register("integrationBootJar", BootJar) {
description = "Assembles an executable JAR archive to be used for integration tests of other projects containing the main classes, their dependencies, and any other integrationImplementation or integrationRuntimeOnly dependencies."
group = 'build'
classpath = sourceSets.main.runtimeClasspath.plus(sourceSets["integration"].runtimeClasspath)
mainClass.set("${jarMainClass}") // TODO can pull from bootJarMainClassName or bootRunMainClassName like bootJar?
archiveClassifier.set("integration")
shouldRunAfter bootJar
}
assemble.dependsOn integrationBootJar
CodePudding user response:
You would need to essentially duplicate the way the Spring Boot plugin creates bootJar
as shown here in the source. Most of the logic is contained within the task itself, so all you have to do is create another BootJar
task type with some slight modifications, mainly adding additional dependencies that are not part of the main JAR.
Complete example (untested):
import org.springframework.boot.gradle.plugin.SpringBootPlugin
import org.springframework.boot.gradle.tasks.bundling.BootJar
plugins {
id("org.springframework.boot") version "2.6.4"
id("java")
}
group = "io.mateo"
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
repositories {
mavenCentral()
}
sourceSets {
register("integrationTest") {
compileClasspath = sourceSets.main.get().output
runtimeClasspath = sourceSets.main.get().output
}
}
val integrationTestImplementation by configurations.getting {
extendsFrom(configurations.implementation.get())
}
dependencies {
implementation(platform(SpringBootPlugin.BOM_COORDINATES))
implementation(platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.1"))
implementation("org.springframework.boot:spring-boot-starter-web")
integrationTestImplementation("org.apache.commons:commons-lang3:3.12.0")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks {
test {
useJUnitPlatform()
}
register("integrationTestBootJar", BootJar::class) {
description = "Assembles an integration test executable JAR archive containing the main classes and their dependencies."
group = BasePlugin.BUILD_GROUP
classpath = sourceSets.main.get().runtimeClasspath.plus(sourceSets["integrationTest"].runtimeClasspath)
mainClass.set("io.mateo.springdemo.SpringdemoApplication")
archiveClassifier.set("integration-test")
}
}
The above integration test configuration is actually an example taken from the Gradle documentation: https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests
In the tasks { }
you can see where the integration test specific Boot JAR is created the same way the Spring Boot plugin creates bootJar
. However, the key difference here is addition of the integration test runtime classpath.