I have a multi-module project with the following build.gradel files
core:
repositories {
mavenCentral()
}
dependencies {
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}
test-module:
dependencies {
implementation project(":core")
}
app:
repositories {
mavenCentral()
}
dependencies {
implementation project(":core")
implementation project(":test")
}
springBoot{
mainClassName = "com.yenovi.dev.Main"
}
and then the root :
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id "io.spring.dependency-management" version "1.0.4.RELEASE"
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'war'
}
repositories {
mavenCentral()
}
subprojects {
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'
apply plugin: "io.spring.dependency-management"
apply plugin: 'org.springframework.boot'
sourceCompatibility = 11
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
}
The core module is supposed to represent the spring boot application, the test module provides extra functionality by creating a Service that is used in Core via dependency injection.
The app module has a main class that calls SpringApplication.run(Core.class, args);. I that app seems useless but at the end, this module will be replaced by separate projects that will use modules from this project.
The problem is that this way the compilation of test fails with an error saying that the package from core can not be found. After some googling I've found that applying the spring boot plugin to all modules causes this issue because it disables the jar task. However without that plugin, the build fails with an error that says that the spring boot starter web dependency can not be found but I need that in all my modules so I can use stuff like the #Service annotation.
How could I solve this?
In Gradle, if you don't specify a version number to the dependencies you use, they need to be supplied by something else. In your case, that something else is the io.spring.dependency-management plugin. However, it only knows about Spring Boot if you also have the org.springframework.boot plugin applied. So once you remove that, the dependency management plugin cannot supply versions for the dependencies anymore.
There are many ways to get around this. Here are the main ones I can think of. All are in Groovy DSL. I list each as a general case, so you will have to adapt it a bit for your project. More specifically, you should remove all plugins from the root (or set them to apply false) and add them to the relevant sub-projects instead. You also likely won't need the war and idea plugins.
(I personally prefer option B by the way.)
A. Use the Spring Dependency Management plugin in isolation
Have the Spring Boot plugin in the list, but don't apply it. This makes the plugin classes available on the project classpath so you can reference it. Then you can give the Spring Boot bom to the dependency management plugin:
plugins {
id 'org.springframework.boot' version '2.4.0' apply false // <- Apply false
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}
See more here.
B. Don't use the Spring Dependency Management plugin
One of the strength of this plugin is if you are migrating from Maven as it mirrors the dependency management rules. There are also a few other features. However, if you are not using those features and are not migrating from Maven, you don't need it. Just use normal Gradle semantics:
plugins {
id 'org.springframework.boot' version '2.4.0' apply false // <- Apply false
id 'java'
}
dependencies {
implementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
implementation 'org.springframework.boot:spring-boot-starter'
}
// OR:
plugins {
id 'java'
}
dependencies {
implementation platform("org.springframework.boot:spring-boot-dependencies:2.4.0")
implementation 'org.springframework.boot:spring-boot-starter'
}
C. Use both plugins, but disable the boot jar task.
The Spring Boot plugin disables the normal jar task, but you can just re-enable it. Because the jar file name is the same in both jar and bootJar, you can't have them both at the same time. So either also disable bootJar or give it a classifier. Here I have disabled it.
plugins {
id 'org.springframework.boot' version '2.4.0' // <- Apply true
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}
jar {
enabled = true
}
bootJar {
enabled = false
}
See more here.
I apologize for the long answer. I got carried away :)
Related
this is my build.gradle
plugins {
// Apply the java-library plugin for API and implementation separation.
id 'java-library'
id 'java'
id 'application'
}
mainClassName = 'myproject.Main'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = '1.0'
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:31.1-jre'
implementation 'com.google.api-client:google-api-client:1.18.0'
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1'
implementation 'com.google.apis:google-api-services-sheets:v4-rev20220927-2.0.0'
}
jar {
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF', 'META-INF/LICENSE', 'META-INF/LICENSE.txt', 'META-INF/DEPENDENCIES', 'META-INF/NOTICE', 'META-INF/NOTICE.txt'
manifest {
attributes 'Main-Class':'myproject.Main'
}
from{
configurations.runtimeClasspath.collect{ it.isDirectory()? it : zipTree(it) }
}
}
after i export my project using eclipse, it got problem when i run it. It seems that it has problem with the dependencies.
i want to export it into runnable jar file that can get data from google spreadsheets
we are facing issue while upgrading gradle 5.6 to gradle 7.2.
we have simple spring boot project(sub1) with one internal spring library project(sub 2). while sub2 is gradle spring lib which depends on sub1. Both projects are using same gradle and spring boot version.
Also we are trying to upgrade spring cloud to latest version which requires gradle upgrade and spring boot upgade. current version is shown below
gradle - 7.2
spring - 2.5.2
swagger - 2.9.2
Getting below error while I try hitting swagger url.
java.lang.IllegalArgumentException: Version must not be null o empty
Spring boot banner is blank and not showing version. we are suspecting this could be the issue.
Swagger home page shows below error:
Failed to load API definition
Gradle file:
repositories {
jcenter()
}
dependencies {
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4+'
}
}
plugins {
id "org.sonarqube" version "2.8"
id "com.gorylenko.gradle-git-properties" version "2.2.2"
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
apply plugin: "jacoco"
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
implementation.canBeResolved = true
}
jar {
archiveVersion = "${project.findProperty('APP_VERSION') ?: 'MANUAL_BUILD'}"
dependsOn configurations.runtimeClasspath
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from {
(configurations.runtimeClasspath-configuration.implementation).collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
dependencies {
implementation('org.springframework:spring-webmvc:5.3.8')
implementation('org.apache.tomcat.embed:tomcat-embed-core:9.0.33')
implementation('org.aspectj:aspectjrt:1.9.5')
}
Please help us understand this issue.
there are some new features added as well as some features from gradle5X removed so, please go through the documentation once again and try to add the below dependencies that may help you in your API.
dependencies {
// Ensure you use the Groovy 3.x variant
testImplementation('org.spockframework:spock-core:2.0-groovy-3.0') {
exclude group: 'org.codehaus.groovy'
}
testImplementation('org.junit.jupiter:junit-jupiter-api')
}
// Spock 2 is based on JUnit Platform and needs to be enabled explicitly.
tasks.withType(Test).configureEach {
useJUnitPlatform()
}
also, go through this once to get more in detailed https://docs.gradle.org/current/userguide/upgrading_version_6.html
I have two modules, first runs Spring boot Application and second it is EventListener which loads files from resources when context starts. All this modules works well separately but I wanna to include event listener module to my first module (Spring boot module) to get all files from resource of my first module when it runs context.
My main module with setting.gradle:
allprojects {
buildDir = file("${rootDir}/build")
group = 'com.example'
version = "0.1.1"
}
subprojects {
apply plugin: 'java'
apply plugin: 'maven'
}
setting.gradle
rootProject.name = 'test-application'
include 'bootApplication'
include 'eventListener'
project(":eventListener").projectDir = file("C:/examples/eventListener")
My bootApplication.gradle:
plugins {
id 'org.springframework.boot' version '2.2.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group 'com.example.bootApplication'
version = "0.1.1"
sourceCompatibility = '11'
targetCompatibility = '11'
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
bootJar {
baseName("bootApplication")
}
jar {
enabled = true
}
dependencies {
compile project(":eventListnere")
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'io.springfox:springfox-swagger2:+'
implementation 'io.springfox:springfox-swagger-ui:+'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
And my eventListener:
plugins {
id 'org.springframework.boot' version '2.2.1.RELEASE'`enter code here`
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group 'com.example.eventlistener'
version '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
targetCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
ext {
spring_boot_version = '2.2.1.RELEASE'
}
implementation "org.springframework.boot:spring-boot-starter:$spring_boot_version"
compileOnly 'org.projectlombok:lombok:1.18.8'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
testImplementation "org.springframework.boot:spring-boot-starter-test:$spring_boot_version"
testCompile group: 'junit', name: 'junit', version: '4.12'
}
jar.enabled = true
When I run my bootApplication main class it creates a eventlistener-.jar file in root build directory. But eventlistener module doesn't check the resource folder, I guess it doesn't see a bootApplication context. Maybe it should be collect to one jar file? It looks like I missed something in gradle build files.
I will just prefix this by saying I don't know if the stuff below is the actual cause of your problems. But you should probably change a few things related to the jar configuration no matter what.
The Spring Boot Gradle plugin is used to create a fat jar out of the project. By default it disables the normal jar task.
You are re-enabling the normal jar task through jar.enabled = true, which is fine. But you also need to give it another name as one will otherwise override the other. For instance, for your eventListener project, you could do this:
// eventListener/build.gradle
bootJar {
classifier = 'boot'
}
However, if the eventListener is not actually a stand-alone executable, there is no need to create a boot jar from it. So unless you are using the plugin for other things, I would remove it from the eventListener completely:
// eventListener/build.gradle
plugins {
// id 'org.springframework.boot' version '2.2.1.RELEASE'`enter code here` <-- Remove this
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
You can still use the Spring Boot starters in the project, you just don't need the plugin for repackaging the jar.
The same thing applies to your bootApplication project: you are both trying to create a fat executable jar at the same time as a normal jar. One will override the other. In this case, you probably don't need the normal jar, so you should disable the jar task again:
// eventListener/build.gradle
// jar.enabled = true <-- Remove this
Lastly, replace compile project(":eventListnere") with implementation project(":eventListener") and testCompile with testImplementation to avoid some deprecation warnings. The maven plugin is deprecated as well in favor of maven-publish. You can probably also get rid of mavenLocal() unless you are integrating with local Maven projects that you build yourself with mvn install.
The eventListener, if packaged correctly as a normal jar inside the fat jar of the bootApplication, should be able to access resources in both its own resource folder as well as the one from bootApplication when you run the latter.
I have been working on multi module gradle project for spring boot devtools. Here is the github repo - GitHub Repo
-spring-boot-dev-tools
-src/main
-java/com/jhooq/springboot/devtools
-resources
-spring-boot-dev-tools.gradle ====- subproject gradle
-.gitignore
-build.gradle ====- main gradle
-gradlew
-gradlew.bat
-settings.gradle
This how my build.gradle(main gradle)looks like : -
buildscript {
ext {
springBootVersion = '2.1.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
allprojects {
group 'com.jhooq'
version '1.0-SNAPSHOT'
}
subprojects{
repositories {
mavenCentral()
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile ("org.springframework.boot:spring-boot-starter")
compile ("org.springframework.boot:spring-boot-starter-test")
}
}
project(':spring-boot-dev-tools'){
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
compile project(':spring-boot-app')
compile ("org.springframework.boot:spring-boot-starter-web")
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
}
So as you can see if i put compile ("org.springframework.boot:spring-boot-starter-web") inside project(':spring-boot-dev-tools') my spring boot application starts on port 8000 and keeps running
But i face issue when i move following gradle scripts inside spring-boot-dev-tools.gradle, then my spring boot application starts and shutdown just like normal spring boot application.
project(':spring-boot-dev-tools'){
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
compile project(':spring-boot-app')
compile ("org.springframework.boot:spring-boot-starter-web")
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
So if i summarize my issue when i move spring spring-boot-starter-web and spring-boot-devtools dependencies inside submodule, spring boot doesn't work/run on port:8000 but instead it starts and shutdown like a normal spring boot application.
Is there a reason why you have defined main class in every separate Java package?
I recently made a modular monolith example which might help you:
modular monolith example
Also some tips to consider:
define a common gradle configuration instead of "allprojects" and "subprojects" keywords. Difference between these two comes down to composition over inheritance
use keyword implementation instead of compile. That way your dependencies do not leak into the compile classpath of consumers anymore. Otherwise use keyword api
I managed to get it working but still the solution is apparently does not feel good to me. But anyways here is what i did -
I moved sub project/module dependency to its own gradle file and removed it from build.gradle(main project gradle)
Instead of "compile project" i switched to "implementation"
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
implementation {
'org.springframework.boot:spring-boot-devtools'
':spring-boot-app'
'org.springframework.boot:spring-boot-starter-web'
}
}
I am trying to use an AspectJ Annotation that is in a Library, that I am pulling into my project. My project uses Gradle, so I am attempting to use FreeFair AspectJ Gradle Plugin.
I need to be able to set the AspectJ -aspectpath argument, to the Library Dependency that Gradle is pulling in.
FreeFair, does not seem to have much Documentation, mainly just Sample Code.
In their sample code, I see that I can use this to set the -aspectpath to a local "project":
aspect project(":aspectj:aspect")
Does anyone know how to set the -aspectpath to an external library dependency?
I created an example Project and put it on GitHub: freefair-aspectpath-external-library.
Note: I am using io.freefair.gradle:aspectj-plugin version 2.9.5 because my project is stuck using Gradle version 4.10.3.
Update: I have created a bug for this: https://github.com/freefair/gradle-plugins/issues/46
Thanks to #larsgrefer, who provided the answer in the GitHub Issue (46).
For the io.freefair.aspectj.compile-time-weaving plugin 2.9.5 the configuration is named "aspects" instead of "aspect".
The following fixed the issue:
aspects project(":aspectj:aspect")
The full build file resembles:
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
// 2.9.5 for use with Gradle 4.10.3.
classpath "io.freefair.gradle:aspectj-plugin:2.9.5"
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: "io.freefair.aspectj.compile-time-weaving"
aspectj.version = '1.9.3'
group 'xyz.swatt'
version '1.0.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
///// SWATT ///// https://mvnrepository.com/artifact/xyz.swatt/swatt
compile group: 'xyz.swatt', name: 'swatt', version: '1.12.0'
aspect "xyz.swatt:swatt:1.12.0"
}
aspect is a plain old gradle configuration.
This means you can use all the notations described here:
https://docs.gradle.org/current/userguide/dependency_types.html#dependency_types
https://docs.gradle.org/current/userguide/declaring_dependencies.html
dependencies {
aspect project(":my-aspect")
aspect "com.example.foo:bar-aspect:1.0.0"
aspect file("foo.jar")
}