Skip to content

Commit 69ce392

Browse files
committed
Add support for classifiers when defining a bom
Closes spring-projectsgh-29298
1 parent a265f15 commit 69ce392

File tree

4 files changed

+130
-13
lines changed

4 files changed

+130
-13
lines changed

buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 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.
@@ -164,13 +164,18 @@ Map<String, DependencyVersion> getProperties() {
164164
return this.properties;
165165
}
166166

167-
String getArtifactVersionProperty(String groupId, String artifactId) {
168-
String coordinates = groupId + ":" + artifactId;
167+
String getArtifactVersionProperty(String groupId, String artifactId, String classifier) {
168+
String coordinates = groupId + ":" + artifactId + ":" + classifier;
169169
return this.artifactVersionProperties.get(coordinates);
170170
}
171171

172172
private void putArtifactVersionProperty(String groupId, String artifactId, String versionProperty) {
173-
String coordinates = groupId + ":" + artifactId;
173+
putArtifactVersionProperty(groupId, artifactId, null, versionProperty);
174+
}
175+
176+
private void putArtifactVersionProperty(String groupId, String artifactId, String classifier,
177+
String versionProperty) {
178+
String coordinates = groupId + ":" + artifactId + ":" + ((classifier != null) ? classifier : "");
174179
String existing = this.artifactVersionProperties.putIfAbsent(coordinates, versionProperty);
175180
if (existing != null) {
176181
throw new InvalidUserDataException("Cannot put version property for '" + coordinates
@@ -186,7 +191,7 @@ private void addLibrary(Library library) {
186191
}
187192
for (Group group : library.getGroups()) {
188193
for (Module module : group.getModules()) {
189-
putArtifactVersionProperty(group.getId(), module.getName(), versionProperty);
194+
putArtifactVersionProperty(group.getId(), module.getName(), module.getClassifier(), versionProperty);
190195
this.dependencyHandler.getConstraints().add(JavaPlatformPlugin.API_CONFIGURATION_NAME,
191196
createDependencyNotation(group.getId(), module.getName(), library.getVersion().getVersion()));
192197
}
@@ -303,7 +308,7 @@ public Object methodMissing(String name, Object args) {
303308
if (arg instanceof Closure) {
304309
ModuleHandler moduleHandler = new ModuleHandler();
305310
ConfigureUtil.configure((Closure<?>) arg, moduleHandler);
306-
return new Module(name, moduleHandler.type, moduleHandler.exclusions);
311+
return new Module(name, moduleHandler.type, moduleHandler.classifier, moduleHandler.exclusions);
307312
}
308313
}
309314
throw new InvalidUserDataException("Invalid configuration for module '" + name + "'");
@@ -315,6 +320,8 @@ public class ModuleHandler {
315320

316321
private String type;
317322

323+
private String classifier;
324+
318325
public void exclude(Map<String, String> exclusion) {
319326
this.exclusions.add(new Exclusion(exclusion.get("group"), exclusion.get("module")));
320327
}
@@ -323,6 +330,10 @@ public void setType(String type) {
323330
this.type = type;
324331
}
325332

333+
public void setClassifier(String classifier) {
334+
this.classifier = classifier;
335+
}
336+
326337
}
327338

328339
}

buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 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.
@@ -109,6 +109,7 @@ private void customizePom(MavenPom pom) {
109109
Node dependencyManagement = findChild(projectNode, "dependencyManagement");
110110
if (dependencyManagement != null) {
111111
addPropertiesBeforeDependencyManagement(projectNode, properties);
112+
addClassifiedManagedDependencies(dependencyManagement);
112113
replaceVersionsWithVersionPropertyReferences(dependencyManagement);
113114
addExclusionsToManagedDependencies(dependencyManagement);
114115
addTypesToManagedDependencies(dependencyManagement);
@@ -136,7 +137,9 @@ private void replaceVersionsWithVersionPropertyReferences(Node dependencyManagem
136137
for (Node dependency : findChildren(dependencies, "dependency")) {
137138
String groupId = findChild(dependency, "groupId").text();
138139
String artifactId = findChild(dependency, "artifactId").text();
139-
String versionProperty = this.bom.getArtifactVersionProperty(groupId, artifactId);
140+
Node classifierNode = findChild(dependency, "classifier");
141+
String classifier = (classifierNode != null) ? classifierNode.text() : "";
142+
String versionProperty = this.bom.getArtifactVersionProperty(groupId, artifactId, classifier);
140143
if (versionProperty != null) {
141144
findChild(dependency, "version").setValue("${" + versionProperty + "}");
142145
}
@@ -188,6 +191,39 @@ private void addTypesToManagedDependencies(Node dependencyManagement) {
188191
}
189192
}
190193

194+
@SuppressWarnings("unchecked")
195+
private void addClassifiedManagedDependencies(Node dependencyManagement) {
196+
Node dependencies = findChild(dependencyManagement, "dependencies");
197+
if (dependencies != null) {
198+
for (Node dependency : findChildren(dependencies, "dependency")) {
199+
String groupId = findChild(dependency, "groupId").text();
200+
String artifactId = findChild(dependency, "artifactId").text();
201+
String version = findChild(dependency, "version").text();
202+
Set<String> classifiers = this.bom.getLibraries().stream()
203+
.flatMap((library) -> library.getGroups().stream())
204+
.filter((group) -> group.getId().equals(groupId))
205+
.flatMap((group) -> group.getModules().stream())
206+
.filter((module) -> module.getName().equals(artifactId)).map(Module::getClassifier)
207+
.filter(Objects::nonNull).collect(Collectors.toSet());
208+
Node target = dependency;
209+
for (String classifier : classifiers) {
210+
if (classifier.length() > 0) {
211+
if (target == null) {
212+
target = new Node(null, "dependency");
213+
target.appendNode("groupId", groupId);
214+
target.appendNode("artifactId", artifactId);
215+
target.appendNode("version", version);
216+
int index = dependency.parent().children().indexOf(dependency);
217+
dependency.parent().children().add(index + 1, target);
218+
}
219+
target.appendNode("classifier", classifier);
220+
}
221+
target = null;
222+
}
223+
}
224+
}
225+
}
226+
191227
private void addPluginManagement(Node projectNode) {
192228
for (Library library : this.bom.getLibraries()) {
193229
for (Group group : library.getGroups()) {

buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 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.
@@ -189,30 +189,37 @@ public static class Module {
189189

190190
private final String type;
191191

192+
private final String classifier;
193+
192194
private final List<Exclusion> exclusions;
193195

194196
public Module(String name) {
195197
this(name, Collections.emptyList());
196198
}
197199

198200
public Module(String name, String type) {
199-
this(name, type, Collections.emptyList());
201+
this(name, type, null, Collections.emptyList());
200202
}
201203

202204
public Module(String name, List<Exclusion> exclusions) {
203-
this(name, null, exclusions);
205+
this(name, null, null, exclusions);
204206
}
205207

206-
public Module(String name, String type, List<Exclusion> exclusions) {
208+
public Module(String name, String type, String classifier, List<Exclusion> exclusions) {
207209
this.name = name;
208210
this.type = type;
211+
this.classifier = (classifier != null) ? classifier : "";
209212
this.exclusions = exclusions;
210213
}
211214

212215
public String getName() {
213216
return this.name;
214217
}
215218

219+
public String getClassifier() {
220+
return this.classifier;
221+
}
222+
216223
public String getType() {
217224
return this.type;
218225
}

buildSrc/src/test/java/org/springframework/boot/build/bom/BomPluginIntegrationTests.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 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.
@@ -75,12 +75,14 @@ void libraryModulesAreIncludedInDependencyManagementOfGeneratedPom() throws IOEx
7575
assertThat(dependency).textAtPath("version").isEqualTo("${activemq.version}");
7676
assertThat(dependency).textAtPath("scope").isNullOrEmpty();
7777
assertThat(dependency).textAtPath("type").isNullOrEmpty();
78+
assertThat(dependency).textAtPath("classifier").isNullOrEmpty();
7879
dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[2]");
7980
assertThat(dependency).textAtPath("groupId").isEqualTo("org.apache.activemq");
8081
assertThat(dependency).textAtPath("artifactId").isEqualTo("activemq-blueprint");
8182
assertThat(dependency).textAtPath("version").isEqualTo("${activemq.version}");
8283
assertThat(dependency).textAtPath("scope").isNullOrEmpty();
8384
assertThat(dependency).textAtPath("type").isNullOrEmpty();
85+
assertThat(dependency).textAtPath("classifier").isNullOrEmpty();
8486
});
8587
}
8688

@@ -135,6 +137,7 @@ void libraryImportsAreIncludedInDependencyManagementOfGeneratedPom() throws Exce
135137
assertThat(dependency).textAtPath("version").isEqualTo("${jackson-bom.version}");
136138
assertThat(dependency).textAtPath("scope").isEqualTo("import");
137139
assertThat(dependency).textAtPath("type").isEqualTo("pom");
140+
assertThat(dependency).textAtPath("classifier").isNullOrEmpty();
138141
});
139142
}
140143

@@ -164,6 +167,7 @@ void moduleExclusionsAreIncludedInDependencyManagementOfGeneratedPom() throws IO
164167
assertThat(dependency).textAtPath("version").isEqualTo("${mysql.version}");
165168
assertThat(dependency).textAtPath("scope").isNullOrEmpty();
166169
assertThat(dependency).textAtPath("type").isNullOrEmpty();
170+
assertThat(dependency).textAtPath("classifier").isNullOrEmpty();
167171
NodeAssert exclusion = dependency.nodeAtPath("exclusions/exclusion");
168172
assertThat(exclusion).textAtPath("groupId").isEqualTo("com.google.protobuf");
169173
assertThat(exclusion).textAtPath("artifactId").isEqualTo("protobuf-java");
@@ -196,10 +200,69 @@ void moduleTypesAreIncludedInDependencyManagementOfGeneratedPom() throws IOExcep
196200
assertThat(dependency).textAtPath("version").isEqualTo("${elasticsearch.version}");
197201
assertThat(dependency).textAtPath("scope").isNullOrEmpty();
198202
assertThat(dependency).textAtPath("type").isEqualTo("zip");
203+
assertThat(dependency).textAtPath("classifier").isNullOrEmpty();
199204
assertThat(dependency).nodeAtPath("exclusions").isNull();
200205
});
201206
}
202207

208+
@Test
209+
void moduleClassifiersAreIncludedInDependencyManagementOfGeneratedPom() throws IOException {
210+
try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {
211+
out.println("plugins {");
212+
out.println(" id 'org.springframework.boot.bom'");
213+
out.println("}");
214+
out.println("bom {");
215+
out.println(" library('Kafka', '2.7.2') {");
216+
out.println(" group('org.apache.kafka') {");
217+
out.println(" modules = [");
218+
out.println(" 'connect-api',");
219+
out.println(" 'generator',");
220+
out.println(" 'generator' {");
221+
out.println(" classifier = 'test'");
222+
out.println(" },");
223+
out.println(" 'kafka-tools',");
224+
out.println(" ]");
225+
out.println(" }");
226+
out.println(" }");
227+
out.println("}");
228+
}
229+
generatePom((pom) -> {
230+
assertThat(pom).textAtPath("//properties/kafka.version").isEqualTo("2.7.2");
231+
NodeAssert connectApi = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[1]");
232+
assertThat(connectApi).textAtPath("groupId").isEqualTo("org.apache.kafka");
233+
assertThat(connectApi).textAtPath("artifactId").isEqualTo("connect-api");
234+
assertThat(connectApi).textAtPath("version").isEqualTo("${kafka.version}");
235+
assertThat(connectApi).textAtPath("scope").isNullOrEmpty();
236+
assertThat(connectApi).textAtPath("type").isNullOrEmpty();
237+
assertThat(connectApi).textAtPath("classifier").isNullOrEmpty();
238+
assertThat(connectApi).nodeAtPath("exclusions").isNull();
239+
NodeAssert generator = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[2]");
240+
assertThat(generator).textAtPath("groupId").isEqualTo("org.apache.kafka");
241+
assertThat(generator).textAtPath("artifactId").isEqualTo("generator");
242+
assertThat(generator).textAtPath("version").isEqualTo("${kafka.version}");
243+
assertThat(generator).textAtPath("scope").isNullOrEmpty();
244+
assertThat(generator).textAtPath("type").isNullOrEmpty();
245+
assertThat(generator).textAtPath("classifier").isNullOrEmpty();
246+
assertThat(generator).nodeAtPath("exclusions").isNull();
247+
NodeAssert generatorTest = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[3]");
248+
assertThat(generatorTest).textAtPath("groupId").isEqualTo("org.apache.kafka");
249+
assertThat(generatorTest).textAtPath("artifactId").isEqualTo("generator");
250+
assertThat(generatorTest).textAtPath("version").isEqualTo("${kafka.version}");
251+
assertThat(generatorTest).textAtPath("scope").isNullOrEmpty();
252+
assertThat(generatorTest).textAtPath("type").isNullOrEmpty();
253+
assertThat(generatorTest).textAtPath("classifier").isEqualTo("test");
254+
assertThat(generatorTest).nodeAtPath("exclusions").isNull();
255+
NodeAssert kafkaTools = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[4]");
256+
assertThat(kafkaTools).textAtPath("groupId").isEqualTo("org.apache.kafka");
257+
assertThat(kafkaTools).textAtPath("artifactId").isEqualTo("kafka-tools");
258+
assertThat(kafkaTools).textAtPath("version").isEqualTo("${kafka.version}");
259+
assertThat(kafkaTools).textAtPath("scope").isNullOrEmpty();
260+
assertThat(kafkaTools).textAtPath("type").isNullOrEmpty();
261+
assertThat(kafkaTools).textAtPath("classifier").isNullOrEmpty();
262+
assertThat(kafkaTools).nodeAtPath("exclusions").isNull();
263+
});
264+
}
265+
203266
@Test
204267
void libraryNamedSpringBootHasNoVersionProperty() throws IOException {
205268
try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {

0 commit comments

Comments
 (0)