diff --git a/initializr-docs/src/main/asciidoc/configuration-format.adoc b/initializr-docs/src/main/asciidoc/configuration-format.adoc index 9ead2e66..e23d3c29 100644 --- a/initializr-docs/src/main/asciidoc/configuration-format.adoc +++ b/initializr-docs/src/main/asciidoc/configuration-format.adoc @@ -90,6 +90,7 @@ with that id is assumed. * A `version` if Spring Boot does not already provide a dependency management for that dependency. * A `scope` (can be `compile`, `runtime`, `provided` or `test`). +* A `classifier` (if the dependency to use is classified, such as `test-jar`). * The reference to a `bom` or a `repository` that must be added to the project once that dependency is added. * A `compatibilityRange` used to determine the platform versions that are compatible diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/Dependency.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/Dependency.java index 2f1963f3..8054158b 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/Dependency.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/Dependency.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,8 @@ public class Dependency { private final DependencyScope scope; + private final String classifier; + private final String type; private final Set exclusions; @@ -50,6 +52,7 @@ public class Dependency { this.artifactId = builder.artifactId; this.version = builder.version; this.scope = builder.scope; + this.classifier = builder.classifier; this.type = builder.type; this.exclusions = new LinkedHashSet<>(builder.exclusions); } @@ -107,6 +110,14 @@ public class Dependency { return this.scope; } + /** + * The classifier of this dependency. Can be {@code null} + * @return the classifier or {@code null} + */ + public String getClassifier() { + return this.classifier; + } + /** * The type of the dependency. Can be {@code null} to indicate that the default type * should be used (i.e. {@code jar}). @@ -142,6 +153,8 @@ public class Dependency { private String type; + private String classifier; + private Set exclusions = new LinkedHashSet<>(); protected Builder(String groupId, String artifactId) { @@ -169,6 +182,11 @@ public class Dependency { return self(); } + public B classifier(String classifier) { + this.classifier = classifier; + return self(); + } + public B type(String type) { this.type = type; return self(); @@ -190,8 +208,8 @@ public class Dependency { } protected B initialize(Dependency dependency) { - version(dependency.getVersion()).scope(dependency.getScope()).type(dependency.getType()) - .exclusions(dependency.getExclusions()); + version(dependency.getVersion()).scope(dependency.getScope()).classifier(dependency.getClassifier()) + .type(dependency.getType()).exclusions(dependency.getExclusions()); return self(); } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriter.java index 10528ae8..780dbf4b 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -134,12 +134,14 @@ public class GroovyDslGradleBuildWriter extends GradleBuildWriter { protected void writeDependency(IndentingWriter writer, Dependency dependency) { String quoteStyle = determineQuoteStyle(dependency.getVersion()); String version = determineVersion(dependency.getVersion()); + String classifier = dependency.getClassifier(); String type = dependency.getType(); boolean hasExclusions = !dependency.getExclusions().isEmpty(); writer.print(configurationForDependency(dependency)); writer.print((hasExclusions) ? "(" : " "); writer.print(quoteStyle + dependency.getGroupId() + ":" + dependency.getArtifactId() - + ((version != null) ? ":" + version : "") + ((type != null) ? "@" + type : "") + quoteStyle); + + ((version != null) ? ":" + version : "") + ((classifier != null) ? ":" + classifier : "") + + ((type != null) ? "@" + type : "") + quoteStyle); if (hasExclusions) { writer.println(") {"); writer.indented( diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriter.java index 992730b0..a3083322 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,10 +149,11 @@ public class KotlinDslGradleBuildWriter extends GradleBuildWriter { @Override protected void writeDependency(IndentingWriter writer, Dependency dependency) { String version = determineVersion(dependency.getVersion()); + String classifier = dependency.getClassifier(); String type = dependency.getType(); writer.print(configurationForDependency(dependency) + "(\"" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ((version != null) ? ":" + version : "") - + ((type != null) ? "@" + type : "") + "\")"); + + ((classifier != null) ? ":" + classifier : "") + ((type != null) ? "@" + type : "") + "\")"); if (!dependency.getExclusions().isEmpty()) { writer.println(" {"); writer.indented( diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriter.java index 1e6fe8ae..6e325ec4 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -213,6 +213,7 @@ public class MavenBuildWriter { writeSingleElement(writer, "artifactId", dependency.getArtifactId()); writeSingleElement(writer, "version", determineVersion(dependency.getVersion())); writeSingleElement(writer, "scope", scopeForType(dependency.getScope())); + writeSingleElement(writer, "classifier", dependency.getClassifier()); if (isOptional(dependency)) { writeSingleElement(writer, "optional", Boolean.toString(true)); } diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/DependencyTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/DependencyTests.java index ae8cecf9..fa080157 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/DependencyTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/DependencyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ class DependencyTests { assertThat(dependency.getArtifactId()).isEqualTo("acme"); assertThat(dependency.getScope()).isNull(); assertThat(dependency.getVersion()).isNull(); + assertThat(dependency.getClassifier()).isNull(); assertThat(dependency.getType()).isNull(); assertThat(dependency.getExclusions()).isEmpty(); } @@ -48,6 +49,19 @@ class DependencyTests { assertThat(dependency.getArtifactId()).isEqualTo("acme"); assertThat(dependency.getScope()).isEqualTo(DependencyScope.RUNTIME); assertThat(dependency.getVersion().getValue()).isEqualTo("1.0.0"); + assertThat(dependency.getClassifier()).isNull(); + assertThat(dependency.getType()).isNull(); + assertThat(dependency.getExclusions()).isEmpty(); + } + + @Test + void dependencyWithClassifier() { + Dependency dependency = Dependency.withCoordinates("com.example", "acme").classifier("test").build(); + assertThat(dependency.getGroupId()).isEqualTo("com.example"); + assertThat(dependency.getArtifactId()).isEqualTo("acme"); + assertThat(dependency.getScope()).isNull(); + assertThat(dependency.getVersion()).isNull(); + assertThat(dependency.getClassifier()).isEqualTo("test"); assertThat(dependency.getType()).isNull(); assertThat(dependency.getExclusions()).isEmpty(); } @@ -59,6 +73,7 @@ class DependencyTests { assertThat(dependency.getArtifactId()).isEqualTo("acme"); assertThat(dependency.getScope()).isNull(); assertThat(dependency.getVersion()).isNull(); + assertThat(dependency.getClassifier()).isNull(); assertThat(dependency.getType()).isEqualTo("test-zip"); assertThat(dependency.getExclusions()).isEmpty(); } @@ -71,6 +86,7 @@ class DependencyTests { assertThat(dependency.getArtifactId()).isEqualTo("acme"); assertThat(dependency.getScope()).isNull(); assertThat(dependency.getVersion()).isNull(); + assertThat(dependency.getClassifier()).isNull(); assertThat(dependency.getType()).isNull(); assertThat(dependency.getExclusions()).containsExactly(new Exclusion("com.example", "exclude1"), new Exclusion("com.example", "exclude2")); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriterTests.java index cdfc3300..ef790fee 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleBuildWriterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -363,6 +363,14 @@ class GroovyDslGradleBuildWriterTests { " testRuntimeOnly 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'", "}"); } + @Test + void gradleBuildWithClassifierDependency() { + GradleBuild build = new GradleBuild(); + build.dependencies().add("root", Dependency.withCoordinates("com.example", "acme").classifier("test-jar")); + List lines = generateBuild(build); + assertThat(lines).containsSequence("dependencies {", " implementation 'com.example:acme:test-jar'", "}"); + } + @Test void gradleBuildWithExclusions() { GradleBuild build = new GradleBuild(); @@ -397,6 +405,16 @@ class GroovyDslGradleBuildWriterTests { " implementation 'org.springframework.boot:spring-boot-starter@tar.gz'", "}"); } + @Test + void gradleBuildWithNonNullArtifactTypeAndClassifierDependency() { + GradleBuild build = new GradleBuild(); + build.dependencies().add("root", Dependency.withCoordinates("com.example", "acme") + .scope(DependencyScope.COMPILE).type("tar.gz").classifier("test-jar")); + List lines = generateBuild(build); + assertThat(lines).containsSequence("dependencies {", " implementation 'com.example:acme:test-jar@tar.gz'", + "}"); + } + @Test void gradleBuildWithBom() { GradleBuild build = new GradleBuild(); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriterTests.java index 8d4a1235..7be12aa0 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleBuildWriterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -371,6 +371,15 @@ class KotlinDslGradleBuildWriterTests { " testRuntimeOnly(\"de.flapdoodle.embed:de.flapdoodle.embed.mongo\")", "}"); } + @Test + void gradleBuildWithClassifierDependency() { + GradleBuild build = new GradleBuild(); + build.dependencies().add("root", Dependency.withCoordinates("com.example", "acme") + .scope(DependencyScope.COMPILE).classifier("test-jar")); + List lines = generateBuild(build); + assertThat(lines).containsSequence("dependencies {", " implementation(\"com.example:acme:test-jar\")", "}"); + } + @Test void gradleBuildWithExclusions() { GradleBuild build = new GradleBuild(); @@ -405,6 +414,16 @@ class KotlinDslGradleBuildWriterTests { " implementation(\"org.springframework.boot:spring-boot-starter@tar.gz\")", "}"); } + @Test + void gradleBuildWithNonNullArtifactTypeAndClassifierDependency() { + GradleBuild build = new GradleBuild(); + build.dependencies().add("root", Dependency.withCoordinates("com.example", "acme") + .scope(DependencyScope.COMPILE).type("tar.gz").classifier("test-jar")); + List lines = generateBuild(build); + assertThat(lines).containsSequence("dependencies {", " implementation(\"com.example:acme:test-jar@tar.gz\")", + "}"); + } + @Test void gradleBuildWithBom() { GradleBuild build = new GradleBuild(); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java index ca63c2cc..96eaf352 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -332,6 +332,19 @@ class MavenBuildWriterTests { }); } + @Test + void pomWithClassifierDependency() { + MavenBuild build = new MavenBuild(); + build.settings().coordinates("com.example.demo", "demo"); + build.dependencies().add("foo-bar", Dependency.withCoordinates("com.example", "acme").classifier("test-jar")); + generatePom(build, (pom) -> { + NodeAssert dependency = pom.nodeAtPath("/project/dependencies/dependency"); + assertThat(dependency).textAtPath("groupId").isEqualTo("com.example"); + assertThat(dependency).textAtPath("artifactId").isEqualTo("acme"); + assertThat(dependency).textAtPath("classifier").isEqualTo("test-jar"); + }); + } + @Test void pomWithExclusions() { MavenBuild build = new MavenBuild(); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenDependencyTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenDependencyTests.java index 12585a7b..df66560b 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenDependencyTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenDependencyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,13 +33,15 @@ class MavenDependencyTests { @Test void initializeFromStandardDependency() { Dependency original = Dependency.withCoordinates("com.example", "test") - .version(VersionReference.ofValue("1.0.0")).scope(DependencyScope.RUNTIME).type("zip").build(); + .version(VersionReference.ofValue("1.0.0")).scope(DependencyScope.RUNTIME).classifier("test-jar") + .type("zip").build(); MavenDependency dependency = MavenDependency.from(original).build(); assertThat(original).isNotSameAs(dependency); assertThat(dependency.getGroupId()).isEqualTo("com.example"); assertThat(dependency.getArtifactId()).isEqualTo("test"); assertThat(dependency.getVersion()).isEqualTo(VersionReference.ofValue("1.0.0")); assertThat(dependency.getScope()).isEqualTo(DependencyScope.RUNTIME); + assertThat(dependency.getClassifier()).isEqualTo("test-jar"); assertThat(dependency.getType()).isEqualTo("zip"); assertThat(dependency.isOptional()).isFalse(); } @@ -47,8 +49,8 @@ class MavenDependencyTests { @Test void initializeFromMavenDependency() { Dependency original = MavenDependency.withCoordinates("com.example", "test") - .version(VersionReference.ofValue("1.0.0")).scope(DependencyScope.RUNTIME).type("zip").optional(true) - .build(); + .version(VersionReference.ofValue("1.0.0")).scope(DependencyScope.RUNTIME).classifier("test-jar") + .type("zip").optional(true).build(); MavenDependency dependency = MavenDependency.from(original).build(); assertThat(original).isNotSameAs(dependency); assertThat(dependency.getGroupId()).isEqualTo("com.example"); @@ -56,6 +58,7 @@ class MavenDependencyTests { assertThat(dependency.getVersion()).isEqualTo(VersionReference.ofValue("1.0.0")); assertThat(dependency.getScope()).isEqualTo(DependencyScope.RUNTIME); assertThat(dependency.getType()).isEqualTo("zip"); + assertThat(dependency.getClassifier()).isEqualTo("test-jar"); assertThat(dependency.isOptional()).isTrue(); } diff --git a/initializr-metadata/src/main/java/io/spring/initializr/metadata/Dependency.java b/initializr-metadata/src/main/java/io/spring/initializr/metadata/Dependency.java index b0732956..824e2f74 100644 --- a/initializr-metadata/src/main/java/io/spring/initializr/metadata/Dependency.java +++ b/initializr-metadata/src/main/java/io/spring/initializr/metadata/Dependency.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,6 +87,8 @@ public class Dependency extends MetadataElement implements Describable { private String version; + private String classifier; + private String type; private List mappings = new ArrayList<>(); @@ -130,6 +132,7 @@ public class Dependency extends MetadataElement implements Describable { this.groupId = dependency.groupId; this.artifactId = dependency.artifactId; this.version = dependency.version; + this.classifier = dependency.classifier; this.type = dependency.type; this.mappings.addAll(dependency.mappings); this.scope = dependency.scope; @@ -325,6 +328,19 @@ public class Dependency extends MetadataElement implements Describable { this.version = version; } + /** + * Return the classifier, can be {@code null} to indicate that no classifier is + * available. + * @return the classifier or {@code null} + */ + public String getClassifier() { + return this.classifier; + } + + public void setClassifier(String classifier) { + this.classifier = classifier; + } + /** * Return the type, can be {@code null} to indicate that the default type should be * used (i.e. {@code jar}). diff --git a/initializr-metadata/src/main/java/io/spring/initializr/metadata/support/MetadataBuildItemMapper.java b/initializr-metadata/src/main/java/io/spring/initializr/metadata/support/MetadataBuildItemMapper.java index 900fd3cc..d8dbd80f 100644 --- a/initializr-metadata/src/main/java/io/spring/initializr/metadata/support/MetadataBuildItemMapper.java +++ b/initializr-metadata/src/main/java/io/spring/initializr/metadata/support/MetadataBuildItemMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,8 @@ public final class MetadataBuildItemMapper { ? VersionReference.ofValue(dependency.getVersion()) : null; return io.spring.initializr.generator.buildsystem.Dependency .withCoordinates(dependency.getGroupId(), dependency.getArtifactId()).version(versionReference) - .scope(toDependencyScope(dependency.getScope())).type(dependency.getType()).build(); + .scope(toDependencyScope(dependency.getScope())).classifier(dependency.getClassifier()) + .type(dependency.getType()).build(); } private static DependencyScope toDependencyScope(String scope) { diff --git a/initializr-metadata/src/test/java/io/spring/initializr/metadata/support/MetadataBuildItemResolverTests.java b/initializr-metadata/src/test/java/io/spring/initializr/metadata/support/MetadataBuildItemResolverTests.java index 2b36dfeb..c30210d3 100644 --- a/initializr-metadata/src/test/java/io/spring/initializr/metadata/support/MetadataBuildItemResolverTests.java +++ b/initializr-metadata/src/test/java/io/spring/initializr/metadata/support/MetadataBuildItemResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,9 @@ class MetadataBuildItemResolverTests { void resoleDependencyWithMatchingEntry() { InitializrMetadata metadata = new InitializrMetadata(); DependencyGroup group = DependencyGroup.create("test"); - group.getContent().add(Dependency.withId("test-dep", "com.example", "test", "1.0.0", "runtime")); + Dependency target = Dependency.withId("test-dep", "com.example", "test", "1.0.0", "runtime"); + target.setClassifier("test-jar"); + group.getContent().add(target); metadata.getDependencies().getContent().add(group); metadata.validate(); MetadataBuildItemResolver resolver = new MetadataBuildItemResolver(metadata, VERSION_2_0_0); @@ -53,6 +55,7 @@ class MetadataBuildItemResolverTests { assertThat(dependency.getGroupId()).isEqualTo("com.example"); assertThat(dependency.getArtifactId()).isEqualTo("test"); assertThat(dependency.getVersion()).hasToString("1.0.0"); + assertThat(dependency.getClassifier()).hasToString("test-jar"); assertThat(dependency.getScope()).isEqualTo(DependencyScope.RUNTIME); }