Add support for dependency exclusions

Closes gh-906
This commit is contained in:
Stephane Nicoll
2019-05-22 11:48:04 +02:00
parent b0597aaca1
commit a2950c9a56
9 changed files with 213 additions and 13 deletions

View File

@@ -16,12 +16,19 @@
package io.spring.initializr.generator.buildsystem;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import io.spring.initializr.generator.version.VersionReference;
import org.springframework.util.Assert;
/**
* A dependency to be declared in a project's build configuration.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class Dependency {
@@ -35,6 +42,8 @@ public class Dependency {
private final String type;
private final Set<Exclusion> exclusions;
public Dependency(String groupId, String artifactId) {
this(groupId, artifactId, DependencyScope.COMPILE);
}
@@ -50,11 +59,17 @@ public class Dependency {
public Dependency(String groupId, String artifactId, VersionReference version,
DependencyScope scope, String type) {
this(groupId, artifactId, version, scope, type, null);
}
public Dependency(String groupId, String artifactId, VersionReference version,
DependencyScope scope, String type, Set<Exclusion> exclusions) {
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
this.scope = scope;
this.type = type;
this.exclusions = (exclusions != null) ? exclusions : Collections.emptySet();
}
/**
@@ -99,4 +114,56 @@ public class Dependency {
return this.type;
}
/**
* The {@link Exclusion exclusions} to apply.
* @return the exclusions to apply
*/
public Set<Exclusion> getExclusions() {
return this.exclusions;
}
/**
* Define the reference to a transitive dependency to exclude.
*/
public static final class Exclusion {
private final String groupId;
private final String artifactId;
public Exclusion(String groupId, String artifactId) {
Assert.hasText(groupId, "GroupId must not be null");
Assert.hasText(groupId, "ArtifactId must not be null");
this.groupId = groupId;
this.artifactId = artifactId;
}
public String getGroupId() {
return this.groupId;
}
public String getArtifactId() {
return this.artifactId;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Exclusion exclusion = (Exclusion) o;
return this.groupId.equals(exclusion.groupId)
&& this.artifactId.equals(exclusion.artifactId);
}
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.artifactId);
}
}
}

View File

@@ -16,9 +16,12 @@
package io.spring.initializr.generator.buildsystem;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.function.Function;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.version.VersionReference;
/**
@@ -72,4 +75,22 @@ public class DependencyContainer extends BuildItemContainer<String, Dependency>
add(id, new Dependency(groupId, artifactId, version, scope, type));
}
/**
* Register a {@link Dependency} with the specified {@code id}, version,
* {@link DependencyScope scope}, type and exclusions.
* @param id the id of the dependency
* @param groupId the groupId
* @param artifactId the artifactId
* @param version the {@link VersionReference}
* @param scope the {@link DependencyScope}
* @param type the artifact type
* @param exclusions the exclusion(s) to apply
*/
public void add(String id, String groupId, String artifactId,
VersionReference version, DependencyScope scope, String type,
Exclusion... exclusions) {
add(id, new Dependency(groupId, artifactId, version, scope, type,
new LinkedHashSet<>(Arrays.asList(exclusions))));
}
}

View File

@@ -145,11 +145,17 @@ public abstract class GradleBuildWriter {
.addAll(filterDependencies(dependencies, DependencyScope.TEST_COMPILE));
sortedDependencies
.addAll(filterDependencies(dependencies, DependencyScope.TEST_RUNTIME));
writeNestedCollection(writer, "dependencies", sortedDependencies,
this::dependencyAsString, writer::println);
if (!sortedDependencies.isEmpty()) {
writer.println();
writer.println("dependencies" + " {");
writer.indented(() -> sortedDependencies
.forEach((dependency) -> writeDependency(writer, dependency)));
writer.println("}");
}
}
protected abstract String dependencyAsString(Dependency dependency);
protected abstract void writeDependency(IndentingWriter writer,
Dependency dependency);
protected String configurationForScope(DependencyScope type) {
switch (type) {
@@ -228,8 +234,8 @@ public abstract class GradleBuildWriter {
}
}
private <T> void writeCollection(IndentingWriter writer, Collection<T> collection,
Function<T, String> converter) {
protected final <T> void writeCollection(IndentingWriter writer,
Collection<T> collection, Function<T, String> converter) {
writeCollection(writer, collection, converter, null);
}

View File

@@ -22,6 +22,7 @@ import java.util.function.BiFunction;
import io.spring.initializr.generator.buildsystem.BillOfMaterials;
import io.spring.initializr.generator.buildsystem.Dependency;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.MavenRepository;
import io.spring.initializr.generator.io.IndentingWriter;
import io.spring.initializr.generator.version.VersionProperty;
@@ -124,14 +125,30 @@ public class GroovyDslGradleBuildWriter extends GradleBuildWriter {
}
@Override
protected String dependencyAsString(Dependency dependency) {
protected void writeDependency(IndentingWriter writer, Dependency dependency) {
String quoteStyle = determineQuoteStyle(dependency.getVersion());
String version = determineVersion(dependency.getVersion());
String type = dependency.getType();
return configurationForScope(dependency.getScope()) + " " + quoteStyle
+ dependency.getGroupId() + ":" + dependency.getArtifactId()
+ ((version != null) ? ":" + version : "")
+ ((type != null) ? "@" + type : "") + quoteStyle;
boolean hasExclusions = !dependency.getExclusions().isEmpty();
writer.print(configurationForScope(dependency.getScope()));
writer.print((hasExclusions) ? "(" : " ");
writer.print(quoteStyle + dependency.getGroupId() + ":"
+ dependency.getArtifactId() + ((version != null) ? ":" + version : "")
+ ((type != null) ? "@" + type : "") + quoteStyle);
if (hasExclusions) {
writer.println(") {");
writer.indented(() -> writeCollection(writer, dependency.getExclusions(),
this::dependencyExclusionAsString));
writer.println("}");
}
else {
writer.println();
}
}
private String dependencyExclusionAsString(Exclusion exclusion) {
return "exclude group: '" + exclusion.getGroupId() + "', module: '"
+ exclusion.getArtifactId() + "'";
}
private String determineQuoteStyle(VersionReference versionReference) {

View File

@@ -23,6 +23,7 @@ import java.util.stream.Collectors;
import io.spring.initializr.generator.buildsystem.BillOfMaterials;
import io.spring.initializr.generator.buildsystem.Dependency;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.MavenRepository;
import io.spring.initializr.generator.buildsystem.gradle.GradleBuild.ConfigurationCustomization;
import io.spring.initializr.generator.buildsystem.gradle.GradleBuild.TaskCustomization;
@@ -131,13 +132,27 @@ public class KotlinDslGradleBuildWriter extends GradleBuildWriter {
}
@Override
protected String dependencyAsString(Dependency dependency) {
protected void writeDependency(IndentingWriter writer, Dependency dependency) {
String version = determineVersion(dependency.getVersion());
String type = dependency.getType();
return configurationForScope(dependency.getScope()) + "(\""
writer.print(configurationForScope(dependency.getScope()) + "(\""
+ dependency.getGroupId() + ":" + dependency.getArtifactId()
+ ((version != null) ? ":" + version : "")
+ ((type != null) ? "@" + type : "") + "\")";
+ ((type != null) ? "@" + type : "") + "\")");
if (!dependency.getExclusions().isEmpty()) {
writer.println(" {");
writer.indented(() -> writeCollection(writer, dependency.getExclusions(),
this::dependencyExclusionAsString));
writer.println("}");
}
else {
writer.println();
}
}
private String dependencyExclusionAsString(Exclusion exclusion) {
return "exclude(group = \"" + exclusion.getGroupId() + "\", module = \""
+ exclusion.getArtifactId() + "\")";
}
@Override

View File

@@ -27,6 +27,7 @@ import java.util.stream.Stream;
import io.spring.initializr.generator.buildsystem.BillOfMaterials;
import io.spring.initializr.generator.buildsystem.Dependency;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.DependencyComparator;
import io.spring.initializr.generator.buildsystem.DependencyContainer;
import io.spring.initializr.generator.buildsystem.DependencyScope;
@@ -158,6 +159,17 @@ public class MavenBuildWriter {
writeSingleElement(writer, "optional", Boolean.toString(true));
}
writeSingleElement(writer, "type", dependency.getType());
if (!dependency.getExclusions().isEmpty()) {
writeElement(writer, "exclusions", () -> writeCollection(writer,
dependency.getExclusions(), this::writeDependencyExclusion));
}
});
}
private void writeDependencyExclusion(IndentingWriter writer, Exclusion exclusion) {
writeElement(writer, "exclusion", () -> {
writeSingleElement(writer, "groupId", exclusion.getGroupId());
writeSingleElement(writer, "artifactId", exclusion.getArtifactId());
});
}

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.DependencyScope;
import io.spring.initializr.generator.io.IndentingWriter;
import io.spring.initializr.generator.test.io.TextTestUtils;
@@ -389,6 +390,21 @@ class GroovyDslGradleBuildWriterTests {
"}");
}
@Test
void gradleBuildWithExclusions() throws IOException {
GradleBuild build = new GradleBuild();
build.dependencies().add("test", "com.example", "test", null,
DependencyScope.COMPILE, null,
new Exclusion("com.example.legacy", "legacy-one"),
new Exclusion("com.example.another", "legacy-two"));
List<String> lines = generateBuild(build);
assertThat(lines).containsSequence("dependencies {",
" implementation('com.example:test') {",
" exclude group: 'com.example.legacy', module: 'legacy-one'",
" exclude group: 'com.example.another', module: 'legacy-two'",
" }", "}");
}
@Test
void gradleBuildWithNonNullArtifactTypeDependency() throws IOException {
GradleBuild build = new GradleBuild();

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.DependencyScope;
import io.spring.initializr.generator.io.IndentingWriter;
import io.spring.initializr.generator.test.io.TextTestUtils;
@@ -393,6 +394,21 @@ class KotlinDslGradleBuildWriterTests {
"}");
}
@Test
void gradleBuildWithExclusions() throws IOException {
GradleBuild build = new GradleBuild();
build.dependencies().add("test", "com.example", "test", null,
DependencyScope.COMPILE, null,
new Exclusion("com.example.legacy", "legacy-one"),
new Exclusion("com.example.another", "legacy-two"));
List<String> lines = generateBuild(build);
assertThat(lines).containsSequence("dependencies {",
" implementation(\"com.example:test\") {",
" exclude(group = \"com.example.legacy\", module = \"legacy-one\")",
" exclude(group = \"com.example.another\", module = \"legacy-two\")",
" }", "}");
}
@Test
void gradleBuildWithNonNullArtifactTypeDependency() throws IOException {
GradleBuild build = new GradleBuild();

View File

@@ -19,6 +19,7 @@ package io.spring.initializr.generator.buildsystem.maven;
import java.io.StringWriter;
import java.util.function.Consumer;
import io.spring.initializr.generator.buildsystem.Dependency.Exclusion;
import io.spring.initializr.generator.buildsystem.DependencyScope;
import io.spring.initializr.generator.io.IndentingWriter;
import io.spring.initializr.generator.test.assertj.NodeAssert;
@@ -255,6 +256,35 @@ class MavenBuildWriterTests {
});
}
@Test
void pomWithExclusions() throws Exception {
MavenBuild build = new MavenBuild();
build.setGroup("com.example.demo");
build.setArtifact("demo");
build.dependencies().add("test", "com.example", "test", null,
DependencyScope.COMPILE, null,
new Exclusion("com.example.legacy", "legacy-one"),
new Exclusion("com.example.another", "legacy-two"));
generatePom(build, (pom) -> {
NodeAssert dependency = pom.nodeAtPath("/project/dependencies/dependency");
assertThat(dependency).textAtPath("groupId").isEqualTo("com.example");
assertThat(dependency).textAtPath("artifactId").isEqualTo("test");
assertThat(dependency).textAtPath("version").isNullOrEmpty();
assertThat(dependency).textAtPath("scope").isNullOrEmpty();
assertThat(dependency).textAtPath("optional").isNullOrEmpty();
NodeAssert exclusions = assertThat(dependency).nodeAtPath("exclusions");
NodeAssert firstExclusion = assertThat(exclusions).nodeAtPath("exclusion[1]");
assertThat(firstExclusion).textAtPath("groupId")
.isEqualTo("com.example.legacy");
assertThat(firstExclusion).textAtPath("artifactId").isEqualTo("legacy-one");
NodeAssert secondExclusion = assertThat(exclusions)
.nodeAtPath("exclusion[2]");
assertThat(secondExclusion).textAtPath("groupId")
.isEqualTo("com.example.another");
assertThat(secondExclusion).textAtPath("artifactId").isEqualTo("legacy-two");
});
}
@Test
void pomWithNonNullArtifactTypeDependency() throws Exception {
MavenBuild build = new MavenBuild();