Skip to content

Commit bdee9c9

Browse files
committed
Ensure consistent versions between dev and production classpaths
Prior to this change, versions in the dev and production classpaths could differ. These differing versions could result in a transitive dependency that should have been present in both development and production only being present in the former. This would likely result in failures at runtime. This commit aligns the versions by adding constraints to the production runtime classpath for each dependency in the runtime classpath. Closes gh-46043
1 parent 640793c commit bdee9c9

File tree

6 files changed

+112
-0
lines changed

6 files changed

+112
-0
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@
2020
import java.util.List;
2121
import java.util.Set;
2222
import java.util.concurrent.Callable;
23+
import java.util.stream.Stream;
2324

2425
import org.gradle.api.Action;
2526
import org.gradle.api.Plugin;
2627
import org.gradle.api.Project;
2728
import org.gradle.api.Task;
2829
import org.gradle.api.artifacts.Configuration;
30+
import org.gradle.api.artifacts.DependencyConstraint;
31+
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
32+
import org.gradle.api.artifacts.dsl.DependencyConstraintHandler;
33+
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
2934
import org.gradle.api.attributes.Attribute;
3035
import org.gradle.api.attributes.AttributeContainer;
3136
import org.gradle.api.file.FileCollection;
@@ -292,6 +297,26 @@ private void configureProductionRuntimeClasspathConfiguration(Project project) {
292297
productionRuntimeClasspath.setExtendsFrom(runtimeClasspath.getExtendsFrom());
293298
productionRuntimeClasspath.setCanBeResolved(runtimeClasspath.isCanBeResolved());
294299
productionRuntimeClasspath.setCanBeConsumed(runtimeClasspath.isCanBeConsumed());
300+
productionRuntimeClasspath.getDependencyConstraints()
301+
.addAllLater(project.getProviders().provider(() -> constraintsFrom(runtimeClasspath, project)));
302+
}
303+
304+
private Iterable<DependencyConstraint> constraintsFrom(Configuration configuration, Project project) {
305+
DependencyConstraintHandler constraints = project.getDependencies().getConstraints();
306+
return resolvedArtifactsOf(configuration).map((artifact) -> artifact.getId().getComponentIdentifier())
307+
.filter(ModuleComponentIdentifier.class::isInstance)
308+
.map(ModuleComponentIdentifier.class::cast)
309+
.map(this::asConstraintNotation)
310+
.map(constraints::create)
311+
.toList();
312+
}
313+
314+
private Stream<ResolvedArtifactResult> resolvedArtifactsOf(Configuration configuration) {
315+
return configuration.getIncoming().getArtifacts().getArtifacts().stream();
316+
}
317+
318+
private String asConstraintNotation(ModuleComponentIdentifier identifier) {
319+
return "%s:%s:%s".formatted(identifier.getGroup(), identifier.getModule(), identifier.getVersion());
295320
}
296321

297322
private void configureDevelopmentOnlyConfiguration(Project project) {

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,21 @@ void developmentOnlyDependenciesCanBeIncludedInTheArchive() throws IOException {
232232
}
233233
}
234234

235+
@TestTemplate
236+
void versionMismatchBetweenTransitiveDevelopmentOnlyImplementationDependenciesDoesNotRemoveDependencyFromTheArchive()
237+
throws IOException {
238+
assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName).getOutcome())
239+
.isEqualTo(TaskOutcome.SUCCESS);
240+
try (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
241+
Stream<String> libEntryNames = jarFile.stream()
242+
.filter((entry) -> !entry.isDirectory())
243+
.map(JarEntry::getName)
244+
.filter((name) -> name.startsWith(this.libPath));
245+
assertThat(libEntryNames).containsExactly(this.libPath + "two-1.0.jar",
246+
this.libPath + "commons-io-2.19.0.jar");
247+
}
248+
}
249+
235250
@TestTemplate
236251
void testAndDevelopmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault() throws IOException {
237252
File srcMainResources = new File(this.gradleBuild.getProjectDir(), "src/main/resources");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
plugins {
2+
id 'java'
3+
id 'org.springframework.boot' version '{version}'
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
maven {
9+
url = 'repository'
10+
}
11+
}
12+
13+
dependencies {
14+
developmentOnly("commons-io-consumer:one:1.0")
15+
implementation("commons-io-consumer:two:1.0")
16+
}
17+
18+
bootJar {
19+
includeTools = false
20+
mainClass = 'com.example.Application'
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
plugins {
2+
id 'war'
3+
id 'org.springframework.boot' version '{version}'
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
maven {
9+
url = 'repository'
10+
}
11+
}
12+
13+
dependencies {
14+
developmentOnly("commons-io-consumer:one:1.0")
15+
implementation("commons-io-consumer:two:1.0")
16+
}
17+
18+
bootWar {
19+
includeTools = false
20+
mainClass = 'com.example.Application'
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>commons-io-consumer</groupId>
6+
<artifactId>one</artifactId>
7+
<version>1.0</version>
8+
<dependencies>
9+
<dependency>
10+
<groupId>commons-io</groupId>
11+
<artifactId>commons-io</artifactId>
12+
<version>2.19.0</version>
13+
</dependency>
14+
</dependencies>
15+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>commons-io-consumer</groupId>
6+
<artifactId>two</artifactId>
7+
<version>1.0</version>
8+
<dependencies>
9+
<dependency>
10+
<groupId>commons-io</groupId>
11+
<artifactId>commons-io</artifactId>
12+
<version>2.18.0</version>
13+
</dependency>
14+
</dependencies>
15+
</project>

0 commit comments

Comments
 (0)