Gradle dependency plugin in a multi module Spring Boot project - gradle

What does a correct Gradle configuration look like in a multi-module project that uses the Gradle plugins spring-boot-dependencies and spring-boot?
I have the following project setup:
parent
|
+ build.gradle
|
+ alpha
| |
| + build.gradle
|
+ beta
| |
| + build.gradle
The parent module contains common project configuration.
The alpha module is a module in which I would like to import dependencies using versions numbers specified in the spring-boot-dependencies bom, but the result of the is a standard jar.
The beta module is a module that depends on alpha and the result is an executable Spring Boot jar file (including all dependencies). Consequently, this project needs both the spring-boot-dependencies as well as the spring-boot plugin.
In order to keep the Gradle files DRY, I have extracted common module scripts to the parent's build.gradle file.
Attempts to execute $ gradle build using the project configuration below results in:
> Plugin with id 'io.spring.dependency-management' not found.
parent gradle.build
allprojects {
group = "com.example"
version '0.0.1-SNAPSHOT'
ext {
dependencyManagementPluginVersion = '0.5.3.RELEASE'
springBootVersion = '1.3.0.RC1'
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
}
subprojects {
sourceCompatibility = 1.8
targetCompatibility = 1.8
buildscript {
repositories {
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}")
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
// mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}")
}
}
}
alpha build.gradle
dependencies {
compile('org.springframework:spring-web')
}
beta gradle.build
apply plugin: 'spring-boot'
dependencies {
compile project(':alpha')
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
}
Comments:
The behavior of the spring-boot plugin was changed in Spring Boot 1.3.0.M1
Gradle version: 2.8
Spring Boot version 1.3.0.RC1

It turns out that parent/build.gradle should be rearranged in the following way:
buildscript {
ext {
dependencyManagementPluginVersion = '0.5.3.RELEASE'
springBootVersion = '1.3.0.RC1'
}
repositories {
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}")
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
allprojects {
group = "com.example"
version '0.0.1-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
}
subprojects {
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
// mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}")
}
}
}
The problem lies in the fact that buildscript block for subprojects was indeed configured well but... in a wrong place. This subprojects block relates to subprojects but it will be evaluated in the script it was declared, and there were no dependencies declared for the plugin it was trying to apply.

Related

How to avoid repeating dependency versions in a multi-module Gradle project?

There's a sample Spring Boot project here that contains two modules.
The build.gradle for one of the modules looks like this:
buildscript {
ext { springBootVersion = '2.1.4.RELEASE' }
repositories { mavenCentral() }
dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }
}
plugins {
id "io.spring.dependency-management" version "1.0.5.RELEASE"
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
bootJar {
baseName = 'gs-multi-module-application'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
compile project(':library')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
The other module's build.gradle looks like this:
buildscript {
repositories { mavenCentral() }
}
plugins { id "io.spring.dependency-management" version "1.0.5.RELEASE" }
ext { springBootVersion = '2.1.4.RELEASE' }
apply plugin: 'java'
apply plugin: 'eclipse'
jar {
baseName = 'gs-multi-module-library'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
}
The springBootVersion = '2.1.4.RELEASE' is declared in both modules. For a 2 module project that might not be a problem, but if my project had 10 modules and I wanted to make sure that all modules always depend on the same version of Spring Boot, it would be inconvenient and error-prone to repeat this version in every module.
Similarly, I might want to add a dependency on commons-io to both of these modules, and ensure they both always depend on the same version of commons-io.
How can I avoid repeating the version numbers in each and every build.gradle file?
See this Gradle documentation : a good practice in Gradle is to configure subprojects which share common traits in a single place, for example in the root project's build script (or using custom plugins)
EDIT the solution proposed here is no longer considered as good practice from Gradle team (the link above does not even mention subproject bloc in latests Gradle version doc); thank you #buggy for the warning .
In your example taken from Spring boot documentation, this pattern could be applied to centralize Spring boot and other common dependencies versions in a single place, but you could go further and also configure other common traits (Java plugin configuration, repositoties, etc..)
Here is how I would re-write the Spring example to make it cleaner and DRY:
Root project
/**
* Add Springboot plugin into build script classpath (without applying it)
* This is this only place where you need to define the Springboot version.
*
* See https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#managing-dependencies-using-in-isolation
*/
plugins {
id "org.springframework.boot" version "2.1.4.RELEASE" apply false
}
// Set version for dependencies share between subprojects
ext {
commonsIoVersion = "2.6"
}
subprojects {
// common config for all Java subprojects
apply plugin: "java"
apply plugin: "eclipse"
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
// apply Spring Boot's dependency management plugin
apply plugin: "io.spring.dependency-management"
}
Library sub-project
// no need for additional plugins
jar {
baseName = 'gs-multi-module-library'
version = '0.0.1-SNAPSHOT'
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter')
implementation "commons-io:commons-io:${commonsIoVersion}"
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
Application sub-project
plugins {
id "org.springframework.boot"
}
bootJar {
baseName = 'gs-multi-module-application'
version = '0.0.1-SNAPSHOT'
}
dependencies {
implementation project(':library')
implementation ('org.springframework.boot:spring-boot-starter-actuator')
implementation ('org.springframework.boot:spring-boot-starter-web')
implementation "commons-io:commons-io:${commonsIoVersion}"
// could also be configured in root project.
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Notes
this solution uses the new plugins {} DSL only (no need for old buildscript block)
version of the io.spring.dependency-management should not be configured explicitly, it will be inherit from Spring boot plugin
You can move the ext{} block to a new file and reference it in your project's build.gradle file via the apply from: statement.
// project/versions.gradle
ext {
springBootVersion = '2.1.4.RELEASE'
}
// project/build.gradle
buildscript {
apply from: 'versions.gradle'
}
// module/build.gradle
dependencies {
implementation "some.dependency:dependency:$springBootVersion"
}
Now you only have to define your dependency versions in one place.
Typically, a project will have a project-level build.gradle file in addition to module-specific build.gradle files. However, the repo you shared is missing the project-level build script. This is why the ext{} block is defined in each module's build script. This is likely not optimal, and I recommend looking at other repos to see how different developers tackled this issue.
There's a Gradle consistent versions plugin that will handle this:
https://github.com/palantir/gradle-consistent-versions
After you set this plugin up in the root build.gradle file, you will create a versions.props file like this, to use the example from the documentation.
com.fasterxml.jackson.*:jackson-* = 2.9.6
com.google.guava:guava = 21.0
com.squareup.okhttp3:okhttp = 3.12.0
junit:junit = 4.12
org.assertj:* = 3.10.0
There's also a versions.locks file, which is auto-generated by ./gradlew --write-locks. You can then specify version-less dependencies in your build.gradle files.

Using spring-boot Gradle plugin but getting spring boot version from dependency management

I have a Gradle setup where I currently need to hard code the spring-boot version. Is it possible to do this with dependency management instead? The issue occurs in my project module that contains the actual code. There I need a call to :
springBoot {
requiresUnpack = ["com.example:util"]
}
In order to do that I need to apply the spring-boot plugin. For that plugin to be available I need to have a dependency to "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}". And for that I need to specify the springBootVersion hard coded...
This is my parent gradle file:
buildscript {
ext {
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
classpath 'io.spring.gradle:dependency-management-plugin:0.6.0.RELEASE'
}
}
plugins {
id "io.spring.dependency-management" version "0.6.0.RELEASE"
}
group 'test'
repositories {
mavenCentral()
}
allprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
// Note that these two BOM's are not always easy to combine, always define cloud first and try to find versions with same version of spring-boot when upgrading.
mavenBom 'org.springframework.cloud:spring-cloud-starter-parent:Brixton.SR5'
mavenBom 'io.spring.platform:platform-bom:2.0.7.RELEASE'
}
}
}
and this is my module gradle file:
group = "test"
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 1.8
targetCompatibility = 1.8
// Temporary fix for jersey
springBoot {
requiresUnpack = ["com.example:util"]
}
If I remove the dependency to spring-boot-gradle-plugin in parent gradle file, then I cannot use the apply plugin: 'spring-boot' in the module gradle file and without that the gradle DLS method springBoot { is not defined...
Can I achieve this without having to hard code springBootVersion = '1.4.0.RELEASE'in my parent gradle file?

How to use Gradle with Spring Boot to get Gosling Release Train of Spring data?

How can I get the latest Gosling release train into my Gradle build file?
I used to be using the 1.1.9.RELEASE group for most of my dependencies. Now I need to fix the problem with RepositoryRestMvcConfiguration mentioned here and to do so I am trying to upgrade to the latest release of spring Data, which has fixed the bug according to the github issue I linked to.
When I added the Gosling release train dependencies I also removed the spring boot starters for spring-data-jpa and spring-data-rest thinking I might have dependency conflicts. Doing this pulled in the new jar files but now I am getting cannot find symbol errors on all my javax.persistence annotations.
Can I use the Gosling release train with the spring boot starters or do I have to figure out how to pull in all spring boot dependencies manually in order to use Gosling?
I am using Gradle 2.3.10 on Mac OS X Yosemite.
New Code
buildscript {
ext {
springBootVersion = '1.3.0.M3'
}
repositories {
jcenter()
mavenCentral()
//maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE"
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: "io.spring.dependency-management"
ext {
springVersion = '4.1.6.RELEASE'
springDataVersion = 'Gosling-RELEASE'
}
dependencyManagement {
imports {
mavenBom "org.springframework:spring-framework-bom:${springVersion}"
mavenBom "org.springframework.data:spring-data-releasetrain:${springDataVersion}"
}
}
jar {
baseName = 'my-data-api'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
//maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-actuator:1.3.0.M3")
compile("org.springframework.boot:spring-boot-starter-aop:1.3.0.M3")
compile 'org.springframework.data:spring-data-jpa'
compile 'org.springframework.data:spring-data-rest-webmvc'
compile("org.springframework.boot:spring-boot-starter-web:1.3.0.M3")
compile("org.springframework.boot:spring-boot-starter-jdbc:1.3.0.M3")
compile('org.antlr:stringtemplate:4.0.2')
compile('org.apache.commons:commons-lang3:3.0')
compile('commons-io:commons-io:2.4')
compile('com.ingres.jdbc:iijdbc:10.0-4.0.5')
testCompile("org.springframework.boot:spring-boot-starter-test:1.3.0.M3")
}
Old code
buildscript {
ext {
springBootVersion = '1.3.0.M2'
}
repositories {
jcenter()
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'my-data-api'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-actuator:1.2.0.RC2")
compile("org.springframework.boot:spring-boot-starter-aop:1.1.9.RELEASE")
compile("org.springframework.boot:spring-boot-starter-data-jpa:1.1.9.RELEASE")
compile("org.springframework.boot:spring-boot-starter-web:1.1.9.RELEASE")
compile("org.springframework.boot:spring-boot-starter-data-rest:1.1.9.RELEASE")
compile("org.springframework.boot:spring-boot-starter-jdbc:1.1.9.RELEASE")
compile('org.antlr:stringtemplate:4.0.2')
compile('org.apache.commons:commons-lang3:3.0')
compile('commons-io:commons-io:2.4')
compile('com.ingres.jdbc:iijdbc:10.0-4.0.5')
testCompile("org.springframework.boot:spring-boot-starter-test:1.1.9.RELEASE")
}
Edit:
If I put a javax persistence dependency in my build.gradle then I can successfully build and use RepositoryRestConfigurerAdapter, but I get runtime problems with dependencies missing for my entityManagerFactory
If you are already using milestone versions of Spring Boot, I suggest you switch to M5. It includes Gosling-RELEASE Spring Data.

Spring Boot Gradle add Native library failed (java.lang.UnsatisfiedLinkError)

I am trying to add a native library( .dll file) to a basic spring gradle project.
I have tried many different settings and all of them didn't work in a basic java project , I have successfully ran that dll file by adding VM argument: java.library.path gradle
here's the script:
buildscript {
ext {
springBootVersion = '1.2.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'messaging'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-aop")
compile("org.springframework.boot:spring-boot-starter-amqp")
compile("org.springframework:spring-messaging")
compile('javax.inject:javax.inject:1')
compile('com.google.guava:guava:11.0.2')
compile('org.codehaus.jackson:jackson-core-asl:1.1.0')
compile('org.codehaus.jackson:jackson-mapper-asl:1.9.13')
testCompile("org.springframework.boot:spring-boot-starter-test")
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
I have tried:
add VM arguments on eclipse
add jvm properties
add gradle system property ( can not succeeded to add that parameter)
I couldn't understand why but when I follow the steps below, it worked:
1. I changed the java package name
2. rebuild the project with gradle
3. run the project

spring-boot gradle plugin can't be found

I have a separate gradle script that is just adding spring-boot plugin. It looks like this:
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url 'http://repo.spring.io/libs-release' }
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.1.8.RELEASE'
}
}
apply plugin: 'spring-boot'
Then, in another project, it is referenced like this:
apply from: '../../food-orders-online-main/spring-boot.gradle'
When I run build task I'm getting the following error:
A problem occurred evaluating script.
> Failed to apply plugin [id 'spring-boot']
> Plugin with id 'spring-boot' not found.
Someone knows what I'm doing wrong?
Applying a plugin by plugin id is not supported in script plugins. You must use the plugin's fully qualified class name.
apply plugin: org.springframework.boot.gradle.plugin.SpringBootPlugin
See this thread for more information.
UPDATE: Updating plugin class name.
These are the Plugins that I am using on spring boot 2.0.1
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
My complete vanilla gradle file here (Spring boot 2.0.5)
buildscript {
ext {
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
OR
there is an even better option, go to the spring starter (spring boot template generating tool) start.spring.io And generate a template project from there, and build step-by-step from there.
This code works for me
plugins{
id 'org.springframework.boot' version '2.0.3.RELEASE'
}
Add:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.4.RELEASE"
}}
Change:
apply plugin: 'spring-boot'
to:
apply plugin: "org.springframework.boot"
Starting from SpringBoot 1.4.0.RELEASE the plugin package has been slightly changed.
apply plugin: org.springframework.boot.gradle.plugin.SpringBootPlugin
Check your syntax and where your parentheses close } I had the same issue and it turned out my repositories { didnt contain } at the end
Got a similar exception
Caused by: org.gradle.internal.resolve.ArtifactNotFoundException: Could not find spring-boot-gradle-plugin-3.0.0-SNAPSHOT.jar (org.springframework.boot:spring-boot-gradle-plugin:3.0.0-SNAPSHOT:20220216.230329-214)
Running the gradle build with --refresh-dependencies fixed it
Below code works for me:-
buildscript {
ext { springBootVersion = '2.0.5.RELEASE'}
repositories { mavenCentral() }
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-
starter-web', version: '2.0.5.RELEASE'
}
After proxy setting ( What is the proxy IP in your organization), I have added following code in build.gradle file. The problem has gone.
sourceSets {
main {
output.setResourcesDir(java.outputDir)
}
}
As of now July first 2020, this is how I was able to configure it, and it worked! Hopefully, this can help anyone facing this problem.
Note: Pay attention to the versions
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath('org.springframework.boot:spring-boot-gradle-plugin:2.2.8.RELEASE')
}
}
plugins {
id 'org.springframework.boot' version '2.2.8.RELEASE'
id 'java'
}
group 'org.capfer'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile('org.springframework.boot:spring-boot-starter-web:2.2.8.RELEASE')
}
could it be, that you don't have a #SpringBootApplication with a main(String[] main) on your classpath ??

Resources