Spring Boot Gradle plugin - Multi Module fat jar - gradle

I have gradle multi-project that looks as follows:
-Project
|
|- common
|- moduleA
|- moduleB
moduleA is Spring Boot app and its gradle build file uses SpringBootGradle plugin. This module depends on common nodule.
moduleB is also Spring Boot app and its gradle build file uses SpringBootGradle plugin. This module depends on moduleA.
After I build my Project with gradle build I expect that moduleA.jar and moduleB.jar exist and they do.
But when I try to run moduleB.jar I get an exception (Spring Boot initialization exception). As I found moduleB.jar contains lib directory with all dependencies from moduleA as well as moduleA.jar (which is packaged with dependencies also).
So what I need is to find a way to add moduleA plain jar as a dependency to my moduleB during the build.

You need to configure module A so that it can be used as a dependency:
bootRepackage {
classifier = 'exec'
}
This will mean that you end up with two jars. One without a classifier that can be used as a dependency, and one with a classifier that is the executable fat jar with dependencies nested inside it.

For Spring Boot 2.3 use
bootJar {
classifier = 'boot' // or whatever
}
The fat jars (for module A and B) will have the name *-boot.jar and module B will include only module-a.jar
See here

Related

Which dependencies are added to a Gradle project which uses a 'project lib dependency' and is this configurable?

Gradle project lib dependencies are a means of defining a project as requiring, as one of its dependencies, the output from another project.
The documentation states:
A “lib” dependency is a special form of an execution dependency. It
causes the other project to be built first and adds the jar with the
classes of the other project to the classpath. It also adds the
dependencies of the other project to the classpath.
However, which dependencies of the project are added? Is it the compile, implementation or runtime dependencies, for instance? Is this configurable? i.e. how would I configure a project to require the output of another project and the dependencies from an arbitrary configuration of that other project?
For instance, in my root project, I can define project1 to depend on project2:
project(":project1") {
dependencies {
implementation project(':project2')
}
}
How do I add the dependencies of an arbitrary configuration of :project2 (let's say it's called myConfiguration) to project1?
The answer is contained within the DSL documentation for Dependencyhandler.
By default, when you declare dependency to projectA, you actually
declare dependency to the 'default' configuration of the projectA. If
you need to depend on a specific configuration of projectA, use map
notation for projects:
configurationName project(path: ':projectA', configuration: 'someOtherConfiguration')

How to build a jar from a multi-module project when using Gradle?

I'm working on a multi-module library project which I build with Gradle. I have a dependency to another module of this project in my dependencies section:
dependencies {
compile project(':my-other-module')
}
My problem is that I want to build a .jar file which only contains the local modules in the final file, not its transitive dependencies. I tried this:
jar {
from project(':my-other-module').configurations.compile.collect { zipTree it }
}
but this added all the transitive dependencies as well. I want to create a .jar which only contains my own files, so the users of this library can have their own versions of transitive dependencies. How can I do so?
Further clarification:
I have dependencies declared in my project to external jars like apache-commons. I want these not to be in my resulting .jar file but I want the users of my library to be able to just add my library as a dependency and let Maven/Gradle download the transitive dependencies. I don't want these transitive dependencies to be in the .jar file I deploy to Maven Central. compileOnly is not an option since the dependencies I use like apache-commons are not provided by a framework or a container. They need to be present as compile dependencies. I just want to build and deploy a .jar file which has all the files in my project which has multiple modules.
I am not sure it'll help you or not but, you can try this.
In your build.gradle file, customize your jar task as follows:
// This closure will return the full directory path of folder where your classes are built
ext.moduleClassPath = { moduleName ->
def classOutputDirConst = "/classes/java/main"
return "${project(":${moduleName}").buildDir}${classOutputDirConst}"
}
// Now jar task will include only the built file of specified project
jar {
from(moduleClassPath("projectName1"), moduleClassPath("projectName2"))
}
Check the reference for the from(SourcePaths) method here: Reference: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object[])
Gradle has a compile-only dependency concept, similar to Maven's provided scope:
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects.
The dependencies you don't want can be declared in the compileOnly configuration, rather than compile, eg:
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
compileOnly is not even visible to unit tests, by default. We change this in a common gradle snippet which we include in each build:
// compileOnly isn't visible to tests by default, add it
plugins.withType(JavaPlugin).whenPluginAdded {
sourceSets {
test.compileClasspath += configurations.compileOnly
test.runtimeClasspath += configurations.compileOnly
}
}
For the second part, for which I believe you want to create a single "fat" jar,
I would suggest creating your jar using the very good Shadow Plugin, rather than manually extending the jar task. By default, the shadow plugin will not include anything in the compileOnly configuration in the resulting jar.

subprojects dependencies failure with Gradle

I'm struggling with Gradle and the build configuration of the following project structure (pretty simple...):
/projA
/projB
/projC
projC using classes from projB.
In projA/settings.gradle:
include 'projB'
include 'projC'
In projC/build.gradle:
dependencies{
compile project(':projB')
}
In IntelliJ I have no problem of dependency resolution, but when I'm running a ./gradlew build in projA, I'm facing a compilation error:
ClassC: Unresolved reference: ClassB
(where ClassC is the class of projC which is failing on the use of ClassB which is a class from projB, obviously...)
Notice that the code is in Kotlin language, that I do not have any problem to run the app in IntelliJ (spring boot run), but any build with Gradle give me an error (both in Intellij and command line).
What am I missing?
Regards,
Adrien
It's a common Gradle idiom to have an additional top level directory for your rootProject. That's a special project that's the parent to all other projects in your build, in a multi-project build.
That's where your settings.gradle file goes:
include ':projA:projB'
include ':projA:projC'
Then, I'd recommend having projA as a subdirectory of your rootProject, so your hierarchy would look as follows:
/myProject
settings.gradle
/projA
build.gradle
/projB
build.gradle
/projC
build.gradle
Also, in projC/build.gradle, you'll want instead:
dependencies {
compile project(':projA:projB')
}
That should do it.

gradle to bundle nested jar dependencies into module output jar

How to make gradle to included some dependencies into module resulted jar as jar? i.e. to make jar with nested jar's e.g. in lib folder ?
This is not Android project, and this should be done for many modules in multi-module project, so fatJar, uberJar, shadowJar alike solutions seem not to fit.
You just need to add an additional from directive to include dependencies in your jar:
task jarJar(type: Jar) {
baseName = project.name + '-jarjar'
from { configurations.compile }
with jar
}

spring boot gradle project with multiple modules not creating fat jar properly

I have a spring boot gradle project with multiple modules in it. The parent project (metadata) is just the root folder for child projects and there are 3 child projects (api, security and ui).
security is a standalone project that uses spring security. here is its pom
dependencies {
compile "org.springframework.boot:spring-boot-starter-security"
compile "com.att.security:csp-cookies:1.0"
compile "javax.servlet:javax.servlet-api"
}
api project uses some of classes from security project so it depends on that
dependencies {
compile ("org.springframework.boot:spring-boot-starter-data-rest") {
exclude module: "spring-boot-starter-tomcat"
}
compile "org.apache.httpcomponents:httpclient:4.4"
compile(project(":metadata-security"))
}
3.finally the UI project is the runnable project that combines everything together.
dependencies {
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile project(":api:metadata-api-invenio")
compile(project(":metadata-security"))
}
When I do gradle build spring boot gradle plugin generates the fat jar for all 3 projects. Upon extracting the jar file it seems like all the transitive deps from all projects are available in the libs folder inside the fat jar. This is good but for some reason the security project jar file is a fat jar and contains its dependencies inside its lib folder which is not needed. In contrast to that, api project jar is not a fat one and only contains its classes because its jars are already available in the ui fat jar.
Any ideas why security project jar is being created different from api project.

Resources