Skip to content

Commit 45e6c12

Browse files
committed
Consider transitives when identifying project dependencies
Previously, when building a layered jar, the Gradle plugin only considered a configuration's direct dependencies when identifying project dependencies. This resulted in transitive project dependencies being missed when deciding which dependencies belong in the application layer. This commit updates ResolvedDependencies to consider all projects from the root project when collecting the IDs of local projects. This ensures that any project dependency, no matter where it appears in the dependency graph, is successfully identified. Fixes gh-25163
1 parent 7cb1605 commit 45e6c12

File tree

6 files changed

+32
-15
lines changed

6 files changed

+32
-15
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -74,15 +74,16 @@ public class BootJar extends Jar implements BootArchive {
7474
*/
7575
public BootJar() {
7676
this.support = new BootArchiveSupport(LAUNCHER, new LibrarySpec(), new ZipCompressionResolver());
77-
this.bootInfSpec = getProject().copySpec().into("BOOT-INF");
78-
this.mainClass = getProject().getObjects().property(String.class);
77+
Project project = getProject();
78+
this.bootInfSpec = project.copySpec().into("BOOT-INF");
79+
this.mainClass = project.getObjects().property(String.class);
7980
configureBootInfSpec(this.bootInfSpec);
8081
getMainSpec().with(this.bootInfSpec);
81-
getProject().getConfigurations().all((configuration) -> {
82+
project.getConfigurations().all((configuration) -> {
8283
ResolvableDependencies incoming = configuration.getIncoming();
8384
incoming.afterResolve((resolvableDependencies) -> {
8485
if (resolvableDependencies == incoming) {
85-
this.resolvedDependencies.processConfiguration(configuration);
86+
this.resolvedDependencies.processConfiguration(project, configuration);
8687
}
8788
});
8889
});

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ResolvedDependencies.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@
2222
import java.util.Set;
2323
import java.util.stream.Collectors;
2424

25+
import org.gradle.api.Project;
2526
import org.gradle.api.artifacts.Configuration;
2627
import org.gradle.api.artifacts.ModuleVersionIdentifier;
27-
import org.gradle.api.artifacts.ProjectDependency;
2828
import org.gradle.api.artifacts.ResolvedArtifact;
2929
import org.gradle.api.artifacts.ResolvedConfiguration;
3030

@@ -44,13 +44,15 @@ class ResolvedDependencies {
4444

4545
private final Map<Configuration, ResolvedConfigurationDependencies> configurationDependencies = new LinkedHashMap<>();
4646

47-
void processConfiguration(Configuration configuration) {
48-
Set<String> projectDependencyIds = configuration.getAllDependencies().withType(ProjectDependency.class).stream()
49-
.map((projectDependency) -> projectDependency.getGroup() + ":" + projectDependency.getName() + ":"
50-
+ projectDependency.getVersion())
47+
private String projectId(Project project) {
48+
return project.getGroup() + ":" + project.getName() + ":" + project.getVersion();
49+
}
50+
51+
void processConfiguration(Project project, Configuration configuration) {
52+
Set<String> localProjectIds = project.getRootProject().getAllprojects().stream().map(this::projectId)
5153
.collect(Collectors.toSet());
5254
this.configurationDependencies.put(configuration,
53-
new ResolvedConfigurationDependencies(projectDependencyIds, configuration.getResolvedConfiguration()));
55+
new ResolvedConfigurationDependencies(localProjectIds, configuration.getResolvedConfiguration()));
5456
}
5557

5658
DependencyDescriptor find(File file) {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void multiModuleImplicitLayers() throws IOException {
149149
assertThat(jarFile.getEntry(layerToolsJar)).isNotNull();
150150
assertThat(jarFile.getEntry("BOOT-INF/lib/alpha-1.2.3.jar")).isNotNull();
151151
assertThat(jarFile.getEntry("BOOT-INF/lib/bravo-1.2.3.jar")).isNotNull();
152+
assertThat(jarFile.getEntry("BOOT-INF/lib/charlie-1.2.3.jar")).isNotNull();
152153
assertThat(jarFile.getEntry("BOOT-INF/lib/commons-lang3-3.9.jar")).isNotNull();
153154
assertThat(jarFile.getEntry("BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar")).isNotNull();
154155
assertThat(jarFile.getEntry("BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar")).isNotNull();
@@ -171,7 +172,8 @@ void multiModuleImplicitLayers() throws IOException {
171172
assertThat(indexedLayers.get("spring-boot-loader")).containsExactly("org/");
172173
assertThat(indexedLayers.get("snapshot-dependencies")).containsExactlyElementsOf(expectedSnapshotDependencies);
173174
assertThat(indexedLayers.get("application")).containsExactly("BOOT-INF/classes/", "BOOT-INF/classpath.idx",
174-
"BOOT-INF/layers.idx", "BOOT-INF/lib/alpha-1.2.3.jar", "BOOT-INF/lib/bravo-1.2.3.jar", "META-INF/");
175+
"BOOT-INF/layers.idx", "BOOT-INF/lib/alpha-1.2.3.jar", "BOOT-INF/lib/bravo-1.2.3.jar",
176+
"BOOT-INF/lib/charlie-1.2.3.jar", "META-INF/");
175177
BuildResult listLayers = this.gradleBuild.build("listLayers");
176178
assertThat(listLayers.task(":listLayers").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
177179
String listLayersOutput = listLayers.getOutput();
@@ -244,6 +246,7 @@ void multiModuleCustomLayers() throws IOException {
244246
assertThat(jarFile.getEntry(layerToolsJar)).isNotNull();
245247
assertThat(jarFile.getEntry("BOOT-INF/lib/alpha-1.2.3.jar")).isNotNull();
246248
assertThat(jarFile.getEntry("BOOT-INF/lib/bravo-1.2.3.jar")).isNotNull();
249+
assertThat(jarFile.getEntry("BOOT-INF/lib/charlie-1.2.3.jar")).isNotNull();
247250
assertThat(jarFile.getEntry("BOOT-INF/lib/commons-lang3-3.9.jar")).isNotNull();
248251
assertThat(jarFile.getEntry("BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar")).isNotNull();
249252
assertThat(jarFile.getEntry("BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar")).isNotNull();
@@ -259,6 +262,7 @@ void multiModuleCustomLayers() throws IOException {
259262
Set<String> expectedSubprojectDependencies = new TreeSet<>();
260263
expectedSubprojectDependencies.add("BOOT-INF/lib/alpha-1.2.3.jar");
261264
expectedSubprojectDependencies.add("BOOT-INF/lib/bravo-1.2.3.jar");
265+
expectedSubprojectDependencies.add("BOOT-INF/lib/charlie-1.2.3.jar");
262266
Set<String> expectedDependencies = new TreeSet<>();
263267
expectedDependencies.add("BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar");
264268
expectedDependencies.add("BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar");
@@ -348,7 +352,7 @@ private boolean isInIndex(List<String> index, String file) {
348352
private void writeSettingsGradle() {
349353
try (PrintWriter writer = new PrintWriter(
350354
new FileWriter(new File(this.gradleBuild.getProjectDir(), "settings.gradle")))) {
351-
writer.println("include 'alpha', 'bravo'");
355+
writer.println("include 'alpha', 'bravo', 'charlie'");
352356
}
353357
catch (IOException ex) {
354358
throw new RuntimeException(ex);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ private void addContent() throws IOException {
323323
return null;
324324
}).given(resolvableDependencies).afterResolve(any(Action.class));
325325
given(configuration.getIncoming()).willReturn(resolvableDependencies);
326-
bootJar.getResolvedDependencies().processConfiguration(configuration);
326+
bootJar.getResolvedDependencies().processConfiguration(bootJar.getProject(), configuration);
327327
}
328328

329329
private ResolvedArtifact mockLibraryArtifact(String fileName, String group, String module, String version) {

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-multiModuleCustomLayers.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ subprojects {
77
apply plugin: 'java'
88
group = 'org.example.projects'
99
version = '1.2.3'
10+
if (it.name == 'bravo') {
11+
dependencies {
12+
implementation(project(':charlie'))
13+
}
14+
}
1015
}
1116

1217
bootJar {

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-multiModuleImplicitLayers.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ subprojects {
77
apply plugin: 'java'
88
group = 'org.example.projects'
99
version = '1.2.3'
10+
if (it.name == 'bravo') {
11+
dependencies {
12+
implementation(project(':charlie'))
13+
}
14+
}
1015
}
1116

1217
bootJar {

0 commit comments

Comments
 (0)