Gradle/Spring Boot generates a file in the boot JAR’s BOOT-INF folder called classpath.idx, and Spring Boot uses a custom classloader to ensure that the order in classpath.idx is honored when Tomcat starts up.
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#appendix.executable-jar.nested-jars.classpath-index
Last year, the order in classpath.idx exactly matched the order in which dependencies are declared in Gradle dependencies (and in projects with subprojects, ordered from root to leaves).
Sometime in the past several months, this regressed, and the order in classpath.idx bears no resemblance to the Gradle dependencies order.
We wrote a post-processor that extracts, corrects, and replaces classpath.idx, but obviously we'd prefer that it not have regressed.
Has nobody else reported this?
Comment From: wilkinsona
We have a test that checks that the index is written and the entries are correctly ordered:
https://github.com/spring-projects/spring-boot/blob/4e62ac458f5682f946e4985d0aee41c8b720c47b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java#L94-L104
If you would like us to spend some more time investigating why things are not working that way for you, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: jimshowalter
This zip contains an intellectual-property-free version of our repo, with everything extraneous removed. It reproduces the problem. For details, see README.md in the root of the project out-of-order-example.zip . (It requires Java 11.)
Comment From: wilkinsona
Thanks for the sample. It's allowed me to determine that the behavior is not caused by Spring Boot. bootJar packages the files in Gradle's runtimeClasspath configuration in the order that's determined by Gradle.
Changing the build.gradle in your sample to the following will reproduce the problem:
apply plugin: 'java-library'
repositories {
mavenCentral()
}
dependencies {
implementation "org.bouncycastle:bc-fips:${bouncyCastleFipsVersion}"
implementation "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}"
implementation "org.bouncycastle:bcprov-jdk15on:${bouncyCastleVersion}"
implementation "org.springframework.data:spring-data-commons:${springDataCommonsVersion}"
implementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
implementation "org.springframework.boot:spring-boot-starter-jersey:${springBootVersion}"
implementation "org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}"
implementation "org.springframework.boot:spring-boot-starter-validation:${springBootVersion}"
implementation "org.springframework.boot:spring-boot-properties-migrator:${springBootVersion}"
// TODO: Why does deleting this fix the out-of-order problem?
implementation "com.box:box-java-sdk:${boxJavaSdkVersion}"
}
tasks.register("dumpRuntimeClasspath") {
doFirst {
configurations.runtimeClasspath.files.each { println it }
}
}
Running ./gradlew dumpRuntimeClasspath will show com.box/box-java-sdk/3.1.2 as the second entry in the runtime classpath:
/Users/awilkinson/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bc-fips/1.0.2.1/3110169183fc532d00f0930f2b5901672515eb7c/bc-fips-1.0.2.1.jar
/Users/awilkinson/.gradle/caches/modules-2/files-2.1/com.box/box-java-sdk/3.1.2/de926dcda010f2ebd3031a1039d2dfe35589a249/box-java-sdk-3.1.2.jar
/Users/awilkinson/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bcpkix-jdk15on/1.57/5c96e34bc9bd4cd6870e6d193a99438f1e274ca7/bcpkix-jdk15on-1.57.jar
/Users/awilkinson/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk15on/1.57/f66a135611d42c992e5745788c3f94eb06464537/bcprov-jdk15on-1.57.jar
…
I can't explain why the ordering in the tree view of the classpath produced by ./gradlew dependencies differs from the ordering of runtimeClasspath.files. I think you'll have to raise that with the Gradle team.