javagradlebuilddependencies

Gradle + Spring Boot: ClassNotFoundException when running custom BootRun task in multi-module project


I have a multi-module Gradle project. Module core is a Spring Boot application with the main class ru.development.core.CoreApplication.

Project structure:

root/
  build.gradle
  settings.gradle
  core/
    src/main/java/ru/development/core/CoreApplication.java
    build.gradle

root/build.gradle

plugins {
    id 'org.springframework.boot' version '3.5.4' apply false
    id 'io.spring.dependency-management' version '1.1.7' apply false
    id 'idea'
}

allprojects {
    group = 'ru.development'
    version = '0.0.1-SNAPSHOT'

    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
    }

    tasks.named('test') {
        useJUnitPlatform()
    }
}

core/build.gradle

import org.springframework.boot.gradle.tasks.run.BootRun

springBoot {
    mainClass.set('ru.development.core.CoreApplication')
}

tasks.register('debug', BootRun) {
    group = 'application'
    description = 'Run Spring Boot with debug'
    args = ['--spring.profiles.active=dev']
    jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005']
    mainClass.set('ru.development.core.CoreApplication')
}

When I run:

gradlew :core:debug

I get:

Listening for transport dt_socket at address: 5005
Error: Could not find or load main class ru.development.core.CoreApplication
Caused by: java.lang.ClassNotFoundException: ru.development.core.CoreApplication

Question:
Why does gradlew :core:debug fail with ClassNotFoundException for CoreApplication, and how can I correctly configure a custom BootRun task for debugging in a multi-module Spring Boot project?


Solution

  • According to https://docs.spring.io/spring-boot/gradle-plugin/running.html

    The bootRun task ... is automatically configured to use the runtime classpath of the main source set.

    In this case, when we register a debug task as tasks.register('debug', BootRun) we will create a new instance of BootRun without any classpath configuration => Gradle can not find the main class.

    To fix this error, just configure the classpath

    tasks.register('debug', BootRun) {
        ...
        // set it using default runtimeClasspath
        classpath = sourceSets.main.runtimeClasspath
    
        // or copy from bootRun task
        classpath = tasks.bootRun.classpath
    }