diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/appendix-configuration-metadata.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/appendix-configuration-metadata.adoc
index 76abbc4361..f02eea3472 100644
--- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/appendix-configuration-metadata.adoc
+++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/appendix-configuration-metadata.adoc
@@ -713,30 +713,6 @@ With Maven the dependency should be declared as optional, as shown in the follow
----
-If you have defined `@ConfigurationProperties` in your application, make sure to configure the `spring-boot-maven-plugin` to prevent the `repackage` goal from adding the dependency into the fat jar:
-
-[source,xml,indent=0,subs="verbatim,quotes,attributes"]
-----
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- org.springframework.boot
- spring-boot-configuration-processor
-
-
-
-
-
-
-
-----
-
With Gradle 4.5 and earlier, the dependency should be declared in the `compileOnly` configuration, as shown in the following example:
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JarTypeFileSpec.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JarTypeFileSpec.java
new file mode 100644
index 0000000000..1b5d38ea32
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JarTypeFileSpec.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.gradle.plugin;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.specs.Spec;
+
+/**
+ * A {@link Spec} for {@link FileCollection#filter(Spec) filtering} {@code FileCollection}
+ * to remove jar files based on their {@code Spring-Boot-Jar-Type} as defined in the
+ * manifest. Jars of type {@code dependencies-starter} are excluded.
+ *
+ * @author Andy Wilkinson
+ */
+class JarTypeFileSpec implements Spec {
+
+ private static final Set EXCLUDED_JAR_TYPES = Collections.singleton("dependencies-starter");
+
+ @Override
+ public boolean isSatisfiedBy(File file) {
+ try (JarFile jar = new JarFile(file)) {
+ String jarType = jar.getManifest().getMainAttributes().getValue("Spring-Boot-Jar-Type");
+ if (jarType != null && EXCLUDED_JAR_TYPES.contains(jarType)) {
+ return false;
+ }
+ }
+ catch (Exception ex) {
+ // Continue
+ }
+ return true;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java
index 164f6a02ee..80fbb2948c 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java
@@ -104,7 +104,8 @@ final class JavaPluginAction implements PluginApplicationAction {
.getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);
Configuration productionRuntimeClasspath = project.getConfigurations()
.getByName(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_NAME);
- return mainSourceSet.getRuntimeClasspath().minus((developmentOnly.minus(productionRuntimeClasspath)));
+ return mainSourceSet.getRuntimeClasspath().minus((developmentOnly.minus(productionRuntimeClasspath)))
+ .filter(new JarTypeFileSpec());
});
bootJar.conventionMapping("mainClassName", new MainClassConvention(project, bootJar::getClasspath));
});
@@ -129,7 +130,7 @@ final class JavaPluginAction implements PluginApplicationAction {
run.setDescription("Runs this project as a Spring Boot application.");
run.setGroup(ApplicationPlugin.APPLICATION_GROUP);
run.classpath(javaPluginConvention(project).getSourceSets().findByName(SourceSet.MAIN_SOURCE_SET_NAME)
- .getRuntimeClasspath());
+ .getRuntimeClasspath().filter(new JarTypeFileSpec()));
run.getConventionMapping().map("jvmArgs", () -> {
if (project.hasProperty("applicationDefaultJvmArgs")) {
return project.property("applicationDefaultJvmArgs");
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java
index 4aa382c482..66055bf2f4 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java
@@ -69,7 +69,8 @@ class WarPluginAction implements PluginApplicationAction {
.getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);
Configuration productionRuntimeClasspath = project.getConfigurations()
.getByName(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_NAME);
- bootWar.setClasspath(bootWar.getClasspath().minus((developmentOnly.minus(productionRuntimeClasspath))));
+ bootWar.setClasspath(bootWar.getClasspath().minus((developmentOnly.minus(productionRuntimeClasspath)))
+ .filter(new JarTypeFileSpec()));
bootWar.conventionMapping("mainClassName", new MainClassConvention(project, bootWar::getClasspath));
});
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java
index fc9b640d52..5a1cba39bd 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java
@@ -17,9 +17,14 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import java.util.stream.Stream;
import org.gradle.testkit.runner.InvalidRunnerConfigurationException;
@@ -172,4 +177,36 @@ abstract class AbstractBootArchiveIntegrationTests {
}
}
+ @TestTemplate
+ void jarTypeFilteringIsApplied() throws IOException {
+ File flatDirRepository = new File(this.gradleBuild.getProjectDir(), "repository");
+ createDependenciesStarterJar(new File(flatDirRepository, "starter.jar"));
+ createStandardJar(new File(flatDirRepository, "standard.jar"));
+ assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName).getOutcome())
+ .isEqualTo(TaskOutcome.SUCCESS);
+ try (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
+ Stream libEntryNames = jarFile.stream().filter((entry) -> !entry.isDirectory())
+ .map(JarEntry::getName).filter((name) -> name.startsWith(this.libPath));
+ assertThat(libEntryNames).containsExactly(this.libPath + "standard.jar");
+ }
+ }
+
+ private void createStandardJar(File location) throws IOException {
+ createJar(location, (attributes) -> {
+ });
+ }
+
+ private void createDependenciesStarterJar(File location) throws IOException {
+ createJar(location, (attributes) -> attributes.putValue("Spring-Boot-Jar-Type", "dependencies-starter"));
+ }
+
+ private void createJar(File location, Consumer attributesConfigurer) throws IOException {
+ location.getParentFile().mkdirs();
+ Manifest manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ attributesConfigurer.accept(attributes);
+ new JarOutputStream(new FileOutputStream(location), manifest).close();
+ }
+
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java
index ec554a81ed..9eaf29bb61 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java
@@ -17,7 +17,12 @@
package org.springframework.boot.gradle.tasks.run;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import org.gradle.api.JavaVersion;
import org.gradle.testkit.runner.BuildResult;
@@ -120,6 +125,17 @@ class BootRunIntegrationTests {
}
}
+ @TestTemplate
+ void jarTypeFilteringIsAppliedToTheClasspath() throws IOException {
+ copyClasspathApplication();
+ File flatDirRepository = new File(this.gradleBuild.getProjectDir(), "repository");
+ createDependenciesStarterJar(new File(flatDirRepository, "starter.jar"));
+ createStandardJar(new File(flatDirRepository, "standard.jar"));
+ BuildResult result = this.gradleBuild.build("bootRun");
+ assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
+ assertThat(result.getOutput()).contains("standard.jar").doesNotContain("starter.jar");
+ }
+
private void copyClasspathApplication() throws IOException {
copyApplication("classpath");
}
@@ -138,4 +154,22 @@ class BootRunIntegrationTests {
return new File(this.gradleBuild.getProjectDir(), path).getCanonicalPath();
}
+ private void createStandardJar(File location) throws IOException {
+ createJar(location, (attributes) -> {
+ });
+ }
+
+ private void createDependenciesStarterJar(File location) throws IOException {
+ createJar(location, (attributes) -> attributes.putValue("Spring-Boot-Jar-Type", "dependencies-starter"));
+ }
+
+ private void createJar(File location, Consumer attributesConfigurer) throws IOException {
+ location.getParentFile().mkdirs();
+ Manifest manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ attributesConfigurer.accept(attributes);
+ new JarOutputStream(new FileOutputStream(location), manifest).close();
+ }
+
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-jarTypeFilteringIsApplied.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-jarTypeFilteringIsApplied.gradle
new file mode 100644
index 0000000000..6e4087cb70
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-jarTypeFilteringIsApplied.gradle
@@ -0,0 +1,25 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '{version}'
+}
+
+bootJar {
+ mainClassName = 'com.example.Application'
+}
+
+repositories {
+ flatDir {
+ dirs 'repository'
+ }
+}
+
+dependencies {
+ implementation(name: "standard")
+ implementation(name: "starter")
+}
+
+bootJar {
+ layered {
+ enabled = false
+ }
+}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle
new file mode 100644
index 0000000000..a4538149be
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle
@@ -0,0 +1,19 @@
+plugins {
+ id 'war'
+ id 'org.springframework.boot' version '{version}'
+}
+
+bootWar {
+ mainClassName = 'com.example.Application'
+}
+
+repositories {
+ flatDir {
+ dirs 'repository'
+ }
+}
+
+dependencies {
+ implementation(name: "standard")
+ implementation(name: "starter")
+}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-jarTypeFilteringIsAppliedToTheClasspath.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-jarTypeFilteringIsAppliedToTheClasspath.gradle
new file mode 100644
index 0000000000..e21adffa8c
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-jarTypeFilteringIsAppliedToTheClasspath.gradle
@@ -0,0 +1,15 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '{version}'
+}
+
+repositories {
+ flatDir {
+ dirs 'repository'
+ }
+}
+
+dependencies {
+ implementation(name: "standard")
+ implementation(name: "starter")
+}
\ No newline at end of file
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java
index fb2a08c5c6..27252f7f8a 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java
@@ -104,6 +104,7 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo {
if (this.excludes != null && !this.excludes.isEmpty()) {
filters.addFilter(new ExcludeFilter(this.excludes));
}
+ filters.addFilter(new JarTypeFilter());
return filters;
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JarTypeFilter.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JarTypeFilter.java
new file mode 100644
index 0000000000..380be01ccd
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JarTypeFilter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.maven;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * A {@link DependencyFilter} that filters dependencies based on the jar type declared in
+ * their manifest.
+ *
+ * @author Andy Wilkinson
+ */
+class JarTypeFilter extends DependencyFilter {
+
+ private static final Set EXCLUDED_JAR_TYPES = Collections
+ .unmodifiableSet(new HashSet<>(Arrays.asList("annotation-processor", "dependencies-starter")));
+
+ JarTypeFilter() {
+ super(Collections.emptyList());
+ }
+
+ @Override
+ protected boolean filter(Artifact artifact) {
+ try (JarFile jarFile = new JarFile(artifact.getFile())) {
+ String jarType = jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Jar-Type");
+ return jarType != null && EXCLUDED_JAR_TYPES.contains(jarType);
+ }
+ catch (IOException ex) {
+ return false;
+ }
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java
index d09eb17284..f901743e43 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java
@@ -16,17 +16,25 @@
package org.springframework.boot.maven;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@@ -39,6 +47,9 @@ import static org.mockito.Mockito.mock;
*/
class DependencyFilterMojoTests {
+ @TempDir
+ static Path temp;
+
@Test
void filterDependencies() throws MojoExecutionException {
TestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), "com.foo");
@@ -97,20 +108,50 @@ class DependencyFilterMojoTests {
assertThat(artifacts).containsExactly(one, three, four);
}
+ @Test
+ void excludeByJarType() throws MojoExecutionException {
+ TestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), "");
+ Artifact one = createArtifact("com.foo", "one", null, "dependencies-starter");
+ Artifact two = createArtifact("com.bar", "two");
+ Set artifacts = mojo.filterDependencies(one, two);
+ assertThat(artifacts).containsExactly(two);
+ }
+
private static Artifact createArtifact(String groupId, String artifactId) {
return createArtifact(groupId, artifactId, null);
}
private static Artifact createArtifact(String groupId, String artifactId, String scope) {
+ return createArtifact(groupId, artifactId, scope, null);
+ }
+
+ private static Artifact createArtifact(String groupId, String artifactId, String scope, String jarType) {
Artifact a = mock(Artifact.class);
given(a.getGroupId()).willReturn(groupId);
given(a.getArtifactId()).willReturn(artifactId);
if (scope != null) {
given(a.getScope()).willReturn(scope);
}
+ given(a.getFile()).willReturn(createArtifactFile(jarType));
return a;
}
+ private static File createArtifactFile(String jarType) {
+ Path jarPath = temp.resolve(UUID.randomUUID().toString() + ".jar");
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+ if (jarType != null) {
+ manifest.getMainAttributes().putValue("Spring-Boot-Jar-Type", jarType);
+ }
+ try {
+ new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest).close();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ return jarPath.toFile();
+ }
+
private static final class TestableDependencyFilterMojo extends AbstractDependencyFilterMojo {
private final ArtifactsFilter[] additionalFilters;
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/JarTypeFilterTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/JarTypeFilterTests.java
new file mode 100644
index 0000000000..ffd929bb7d
--- /dev/null
+++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/JarTypeFilterTests.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.maven;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.maven.artifact.Artifact;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link JarTypeFilter}.
+ *
+ * @author Andy Wilkinson
+ */
+class JarTypeFilterTests {
+
+ @TempDir
+ Path temp;
+
+ @Test
+ void whenArtifactHasNoJarTypeThenItIsIncluded() {
+ assertThat(new JarTypeFilter().filter(createArtifact(null))).isFalse();
+ }
+
+ @Test
+ void whenArtifactHasJarTypeThatIsNotExcludedThenItIsIncluded() {
+ assertThat(new JarTypeFilter().filter(createArtifact("something-included"))).isFalse();
+ }
+
+ @Test
+ void whenArtifactHasDependenciesStarterJarTypeThenItIsExcluded() {
+ assertThat(new JarTypeFilter().filter(createArtifact("dependencies-starter"))).isTrue();
+ }
+
+ @Test
+ void whenArtifactHasAnnotationProcessorJarTypeThenItIsExcluded() {
+ assertThat(new JarTypeFilter().filter(createArtifact("annotation-processor"))).isTrue();
+ }
+
+ private Artifact createArtifact(String jarType) {
+ Path jarPath = this.temp.resolve("test.jar");
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+ if (jarType != null) {
+ manifest.getMainAttributes().putValue("Spring-Boot-Jar-Type", jarType);
+ }
+ try {
+ new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest).close();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ Artifact artifact = mock(Artifact.class);
+ given(artifact.getFile()).willReturn(jarPath.toFile());
+ return artifact;
+ }
+
+}