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

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.

Related

Convert gradle multi project to springboot fat jar application

I had a http servlet application which was a multi project gradle build, where my project was a contain gradle HttpServlet project and it depends on the other two gradle java projects. I deployed all the 3 jars in the tomcat webapps/Web-INF/lib directory and run it.
Now there is a requirement that I have to convert my application as a spring boot application and instead of 3 separate jars I have to create a fat jar which I should run it.
I don’t have much experience with grade and spring boot. I was wondering how can I create a fat jar from the multi gradle project.?
I converted my http servlet project to a spring boot project but I am confused that how I will refer the other gradle projects in the springboot project and create a single fat jar? Please see the directory structure of the projects
Rootrepository
- Springboot project
-src….
- OtherGardleProject1
- Src…
- OtherGardleProject2
- Src…
Can someone please share some pointer?
You could use a top-level settings.gradle file that includes the main app and the libraries
Rootrepository
- settings.gradle
- Springboot project
- build.gradle
-src….
- OtherGardleProject1
- Src…
- OtherGardleProject2
- Src…
The settings.gradle looks like this:
include: ':Springboot project', ':OtherGardleProject1', ':OtherGardleProject2'
Then in the build.gradle of the Springboot project module you add the dependencies to the libraries
plugins {
id 'org.springframework.boot' version '2.0.3.RELEASE'
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
...
dependencies {
compile project(':OtherGardleProject1')
compile project(':OtherGardleProject2')
...
}
After you build the project, the jar in Sprinboot project/build/libs folder should contain the classes of the app and the other two modules as jar files.
Hope it helps.

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.

Spring Boot Gradle plugin - Multi Module fat jar

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

Gradle include jar produced by another project in war

Currently I have two projects with gradle build.gradle. The first is going to create a fat jar file, which I would like to include in a war file. I thought compiling it would be enough, but it doesn't seem to be ending up in the /lib directory of my war file. Anyone have thoughts I am quite new to gradle.
dependencies {
compile project(':JarProject')
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedCompile 'org.apache.tomcat:tomcat-jsp-api:7.0.55'
}
war {
archiveName 'WarProject.war'
from 'JarProject/build/libs'
webXml = file('src/web.xml')
}
Does the second project war need to be in providedRuntime? Or should I publish the jar from the other project in the local maven repo and include it that way?
The War task essentially behaves like a CopyTask with regards to stuff it packs in the war, so the documentation on working with files is useful. In essence, I think you need something like (untested):
from fileTree('JarProject/build/libs') {
into("lib")
}
That being said, using mavenLocal() and publishing there also works, but it can lead to unexpected results when the war includes some old version from local, picking up the jar explicitly from the file system like above is better.
I think the elegant solution would be to use multi project builds and project level dependencies. You would have the two builds as separate projects of the same Gradle build and add the "jar project" as a regular compile dependency.
How have you declared the dependency? I assume you have a multi-project build with subprojects A and B, both using the War plugin. I made an experiment using Gradle 2.4 and if I declare B/build.gradle like this:
apply plugin: 'war'
dependencies {
compile project(':A')
}
then B.war contains WEB-INF/lib/A.jar. If you correctly follow conventions of Gradle War plugin (place web resources in A/src/main/webapp/ and code-related resources in A/src/main/resources/), then A.jar should contain what you want.
see this

Is there a way to add classpath/directories for dependencies on Gradle?

I have a new project, it depends on classes at legacy project, not jar files but actual classes.
How can I make these directories a dependency for gradle compile?
dependencies {
compile files("relative/path/to/classes/dir")
}
For further details, check out the Gradle User Guide.

Resources