Due to some requirements with the xjc plugin, I need to declare multiple sourceSets in my project, and gather outputs of these sourcesets in the bootjar archive.

I managed to do this with the following configuration:

sourceSets {
    set1
    set2 
    main {
        compileClasspath += set1.output
        runtimeClasspath += set1.output

        compileClasspath += set2.output
        runtimeClasspath += set2.output
    }
}

With Springboot 2.3.X.RELEASE, I am able to launch the application with Bootrun task, and Bootjar worked like it should according to Gradle plugins documentation :

Creates a BootJar task named bootJar that will create an executable, fat jar for the project. The jar will contain everything on the runtime classpath of the main source set; classes are packaged in BOOT-INF/classes and jars are packaged in BOOT-INF/lib

When upgrading to springboot >= 2.4.0 bootrun task started to complain about ClassNotFoundException with other sourcesets classes (although these classes are build and exist on the filesystem), and these .class files are not included in the generated bootjar.

If this is the expected behaviour, the documentation should be fixed as it is misleading.

A demo project is available here to illustrate this issue.

Comment From: wilkinsona

Thanks for the report. I suspect that the change in behaviour is due to https://github.com/spring-projects/spring-boot/issues/22922 where we added support for Gradle's configuration cache. As part of those changes, we started configuring bootJar and bootRun's classpath directly rather than via a Callable. Removing this deferred access to the project met the configuration cache's requirements but I think it has had the unintended side-effect of losing changes to the main source set's classpath that are made after Boot's plugin has been applied.

Comment From: wilkinsona

@elvay1 You can work around the current behaviour by configuring the main source set's classpath before you apply Spring Boot's plugin:

plugins {
    id 'org.springframework.boot' version '2.4.0' apply false
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group 'org.example.demo'
version '1.0'
sourceCompatibility = '11'

sourceSets {
    second
    main {
        compileClasspath += second.output;
        runtimeClasspath += second.output;
    }
}

apply plugin: 'org.springframework.boot'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
}

test {
    useJUnitPlatform()
}

Comment From: wilkinsona

Gradle's war plugin uses a Callable to configure the classpath and supports the configuration cache. Perhaps we went too far in https://github.com/spring-projects/spring-boot/issues/22922 or some of the configuration cache's limitations have been addressed in more recent versions of Gradle. We should explore the possibility of using a Callable again.