I have the following project structure:
RootProject
├── lib
└── src
└── main
└── java
└── ...
├── test-project
└── src
└── main
└── java
└── ...
└── build.gradle
I trying to follow Gradle best practices for multi project builds, and therefore I describing the whole build process in single build.gradle file.
"RootProject" is just a root project without any code and its single purpose is to provide a single build.gradle for its subprojects: "lib" and "test-project".
"test-project" is a SpringBoot project (micro service) using "lib" as compile dependency.
My common build.gradle looks as the following:
plugins{
id 'java'
id 'org.springframework.boot' version '2.1.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
}
allprojects {
repositories {
jcenter()
}
}
subprojects {
apply plugin: 'io.spring.dependency-management'
apply plugin: 'org.springframework.boot'
group = 'com.xxx.yyy'
version = '1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
project(":lib"){
apply plugin: 'java-library'
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}
bootJar { enabled = false }
jar { enabled = true }
}
project(":test-project"){
apply plugin: 'java'
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
implementation project(":lib")
implementation ('mysql:mysql-connector-java')
}
}
Both "lib" and "test-project" are built successfully. However, when I trying to execute "bootJar" task on root project (which supposed to trigger "build" task on all subprojects) I getting the following error:
Main class name has not been configured and it could not be resolved
Any ideas?
Spring Boot allows us to define the Main class in the configuration when we have multiple main classes declared in the application. As we are using a MAVEN build, we have to configure the POM. xml for Spring Boot to identify the main class of the application. Voila!
When we apply the java plugin, the Spring Boot Gradle plugin takes multiple actions like: creating a bootJar task, which we can use to generate an executable jar file. creating a bootRun task, which we can use to run our application directly. disabling jar task.
The Spring Boot Gradle Plugin provides Spring Boot support in Gradle. It allows you to package executable jar or war archives, run Spring Boot applications, and use the dependency management provided by spring-boot-dependencies . Spring Boot's Gradle plugin requires Gradle 6.8, 6.9, or 7.
An intro on multi-project build best practices
When you say:
I trying to follow Gradle best practices for multi project builds, and therefore I describing the whole build process in single build.gradle file.
I don't think this is actually is a good practice, and this is not what is really recommended inthe guide you mentioned.
In the guide intro:
While each subproject could configure itself in complete isolation of the other subprojects, it is common that subprojects share common traits. It is then usually preferable to share configurations among projects, so the same configuration affects several subprojects.
=> Indeed, common traits shared between subprojects should be configured in a central place in root project build.
Later in the guide (in this section ) there is a example with subprojects specific configuration defined in the root project script , but there is a note in the example description:
All the build logic is in the build script of the root project.(2)
(2): We do this here, as it makes the layout a bit easier. We usually put the project specific stuff into the build script of the respective projects.
Regarding your issue
I make assumption that your lib
project is a plain "simple" java lib project (no Spring or SpringBoot dependencies), and test-project
is the project containing the SpringBoot application classes (specially the @SpringBootApplication
main application class).
Following best practices described above, you should then have three distinct project build scripts:
root project
: used to defined common configuration share in subproject (java plugin configuration, repositories, shared dependencies, etc...)lib
project : specific configuration for this lib project (java-library plugin, specific dependencies, ...)
spring-boot
plugin to this sub-project, and this is actually the cause for your error "cannot find main class"io.spring.dependency-management
plugin (in this cas it would make sense to apply this dependecy plugin in the root project build, to use same Spring version in both subprojects)test-project
project: configuration related to Spring Boot application (SpringBoot plugin and dependencies)Example
root project build
ext{
slf4jVersion = "1.7.25"
}
subprojects {
apply plugin: "java"
// if both subprojects share some Spring related dependencies, apply the Spring `io.spring.dependency-management` here.
group = 'com.xxx.yyy'
version = '1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
}
}
'lib' project build
plugins{
id 'java-library'
}
dependencies {
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
// lib dependencies
}
'test-project' build
plugins {
id "org.springframework.boot" version "2.1.1.RELEASE"
}
apply plugin: 'io.spring.dependency-management'
dependencies {
implementation project(":lib")
implementation('org.springframework.boot:spring-boot-starter-web')
testImplementation('org.springframework.boot:spring-boot-starter-test')
implementation ('mysql:mysql-connector-java')
// ...
}
EDIT as per your comment: if lib
project requires Spring Data related stuff, apply the io.spring.dependency-management
as follows ( see more details in Spring reference guide)
plugins{
id 'java-library'
id "org.springframework.boot" version "2.1.1.RELEASE" apply false
}
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// lib dependencies
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With