From 15501eaafb4367d3100b6f791a7f7269937d577d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 6 May 2014 14:54:09 +0200 Subject: [PATCH] Exclude support in the maven plugin This commit provides several options to exclude one or more dependencies: * excludes allows to specify an arbitrary number of exclude sub element defining the groupId and artifactId of the dependency to exclude * excludedGroupIds defines the comma separated list of groupIds to exclude * excludeArtifactIds defines the comma separated list of artifactIds to exclude While any artifact can be excluded, this is designed to exclude provided-scoped dependencies that should not be bundled in the executable jar/war. The outcome of java -jar myapp.jar should be consistent with the run goal: these exclusions are therefore applied to the classpath that the run goal computes to launch the application. This commit also adds some integration tests and updates the plugin's documentation Fixes gh-649, gh-650 and gh-674 --- spring-boot-parent/pom.xml | 5 + .../spring-boot-maven-plugin/pom.xml | 4 + .../src/it/jar-exclude-artifact/pom.xml | 61 ++++++++ .../main/java/org/test/SampleApplication.java | 8 ++ .../src/it/jar-exclude-artifact/verify.groovy | 11 ++ .../src/it/jar-exclude-entry/pom.xml | 82 +++++++++++ .../main/java/org/test/SampleApplication.java | 8 ++ .../src/it/jar-exclude-entry/verify.groovy | 27 ++++ .../src/it/jar-exclude-group/pom.xml | 76 ++++++++++ .../main/java/org/test/SampleApplication.java | 8 ++ .../src/it/jar-exclude-group/verify.groovy | 27 ++++ .../src/it/jar-test-scope/pom.xml | 61 ++++++++ .../main/java/org/test/SampleApplication.java | 8 ++ .../src/it/jar-test-scope/verify.groovy | 27 ++++ .../src/it/run-exclude/pom.xml | 56 ++++++++ .../main/java/org/test/SampleApplication.java | 27 ++++ .../src/it/run-exclude/verify.groovy | 3 + .../src/it/run/pom.xml | 1 - .../maven/AbstractDependencyFilterMojo.java | 111 +++++++++++++++ .../springframework/boot/maven/Exclude.java | 70 ++++++++++ .../boot/maven/ExcludeFilter.java | 88 ++++++++++++ .../boot/maven/RepackageMojo.java | 13 +- .../springframework/boot/maven/RunMojo.java | 32 +++-- .../apt/examples/exclude-dependency.apt.vm | 117 ++++++++++++++++ ...sifier.apt => repackage-classifier.apt.vm} | 0 .../src/site/apt/index.apt | 2 + .../src/site/apt/usage.apt.vm | 21 ++- .../src/site/site.xml | 1 + .../boot/maven/DependencyFilterMojoTests.java | 85 ++++++++++++ .../boot/maven/ExcludeFilterTests.java | 131 ++++++++++++++++++ .../boot/maven/RepackageMojoTests.java | 44 ++++++ .../springframework/boot/maven/Verify.java | 121 +++++++++++----- 32 files changed, 1282 insertions(+), 54 deletions(-) create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/pom.xml create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/verify.groovy create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/pom.xml create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/verify.groovy create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/pom.xml create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/verify.groovy create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/pom.xml create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/verify.groovy create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/pom.xml create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/verify.groovy create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ExcludeFilter.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/exclude-dependency.apt.vm rename spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/{repackage-classifier.apt => repackage-classifier.apt.vm} (100%) create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ExcludeFilterTests.java create mode 100644 spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/RepackageMojoTests.java diff --git a/spring-boot-parent/pom.xml b/spring-boot-parent/pom.xml index d1ecb8f34d6..3bba7234848 100644 --- a/spring-boot-parent/pom.xml +++ b/spring-boot-parent/pom.xml @@ -98,6 +98,11 @@ maven-settings-builder ${maven.version} + + org.apache.maven.shared + maven-common-artifact-filters + 1.4 + org.apache.maven.plugins maven-shade-plugin diff --git a/spring-boot-tools/spring-boot-maven-plugin/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/pom.xml index 93b94ea879a..47cb11090e9 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/pom.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/pom.xml @@ -126,6 +126,10 @@ org.apache.maven maven-settings + + org.apache.maven.shared + maven-common-artifact-filters + org.codehaus.plexus plexus-archiver diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/pom.xml new file mode 100644 index 00000000000..02747a078df --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-exclude-artifact + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + servlet-api + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + Foo + + + + + + + + + org.springframework + spring-context + 3.2.3.RELEASE + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + javax.servlet + servlet-api + 2.5 + provided + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..0b3b431677d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,8 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/verify.groovy new file mode 100644 index 00000000000..be667d68820 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-artifact/verify.groovy @@ -0,0 +1,11 @@ +import java.io.*; +import org.springframework.boot.maven.*; + +File f = new File( basedir, "target/jar-exclude-artifact-0.0.1.BUILD-SNAPSHOT.jar"); +new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { + @Override + protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { + super.verifyZipEntries(verifier) + verifier.assertHasNoEntryNameStartingWith("lib/servlet-api-2.5.jar") + } +}.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/pom.xml new file mode 100644 index 00000000000..00bdeb2f851 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/pom.xml @@ -0,0 +1,82 @@ + + + + + 4.0.0 + org.springframework.boot.maven.it + jar-exclude-entry + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + + javax.servlet + servlet-api + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + Foo + + + + + + + + + org.springframework + spring-context + 3.2.3.RELEASE + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + javax.servlet + servlet-api + 2.5 + provided + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..0b3b431677d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,8 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/verify.groovy new file mode 100644 index 00000000000..4f27fc368d9 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-entry/verify.groovy @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2014 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 + * + * http://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. + */ + +import java.io.*; +import org.springframework.boot.maven.*; + +File f = new File( basedir, "target/jar-exclude-entry-0.0.1.BUILD-SNAPSHOT.jar"); +new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { + @Override + protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { + super.verifyZipEntries(verifier) + verifier.assertHasNoEntryNameStartingWith("lib/servlet-api-2.5.jar") + } +}.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/pom.xml new file mode 100644 index 00000000000..c8bae6c3a78 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/pom.xml @@ -0,0 +1,76 @@ + + + + + 4.0.0 + org.springframework.boot.maven.it + jar-exclude-group + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + log4j + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + Foo + + + + + + + + + org.springframework + spring-context + 3.2.3.RELEASE + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + log4j + log4j + 1.2.17 + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..0b3b431677d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,8 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/verify.groovy new file mode 100644 index 00000000000..f03bbb3a839 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-exclude-group/verify.groovy @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2014 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 + * + * http://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. + */ + +import java.io.*; +import org.springframework.boot.maven.*; + +File f = new File( basedir, "target/jar-exclude-group-0.0.1.BUILD-SNAPSHOT.jar"); +new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { + @Override + protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { + super.verifyZipEntries(verifier) + verifier.assertHasNoEntryNameStartingWith("lib/log4j-1.2.17.jar") + } +}.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/pom.xml new file mode 100644 index 00000000000..1426be6b19d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-test-scope + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + servlet-api + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + Foo + + + + + + + + + org.springframework + spring-context + 3.2.3.RELEASE + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + log4j + log4j + 1.2.17 + test + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..0b3b431677d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,8 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/verify.groovy new file mode 100644 index 00000000000..b76415b150b --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-test-scope/verify.groovy @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2014 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 + * + * http://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. + */ + +import java.io.*; +import org.springframework.boot.maven.*; + +File f = new File( basedir, "target/jar-test-scope-0.0.1.BUILD-SNAPSHOT.jar"); +new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { + @Override + protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { + super.verifyZipEntries(verifier) + verifier.assertHasNoEntryNameStartingWith("lib/log4j-1.2.17.jar") + } +}.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/pom.xml new file mode 100644 index 00000000000..f48531ad0cc --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-exclude + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + package + + run + + + + + log4j + log4j + + + javax.servlet + + + + + + + + + log4j + log4j + 1.2.17 + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + javax.servlet + servlet-api + 2.5 + provided + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..6f0d38785a0 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,27 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + if (isClassPresent("org.apache.log4j.Logger")) { + throw new IllegalStateException("Log4j was present and should not"); + } + if (isClassPresent("javax.servlet.Servlet")) { + throw new IllegalStateException("servlet-api was present and should not"); + } + System.out.println("I haz been run"); + } + + private static boolean isClassPresent(String className) { + + try { + ClassLoader classLoader = SampleApplication.class.getClassLoader(); + classLoader.loadClass(className); + return true; + } + catch (ClassNotFoundException e) { + return false; + } + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/verify.groovy new file mode 100644 index 00000000000..841c4a97de5 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/run-exclude/verify.groovy @@ -0,0 +1,3 @@ +def file = new File(basedir, "build.log") +return file.text.contains("I haz been run") + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/run/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/run/pom.xml index af6bbbc2c78..092e362c671 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/run/pom.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/run/pom.xml @@ -16,7 +16,6 @@ @project.version@ - package run diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java new file mode 100644 index 00000000000..954735dded3 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2014 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 + * + * http://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.util.List; +import java.util.Set; +import java.util.StringTokenizer; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException; +import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter; +import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; +import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter; + +/** + * A base mojo filtering the dependencies of the project. + * + * @author Stephane Nicoll + * @since 1.1 + */ +public abstract class AbstractDependencyFilterMojo extends AbstractMojo { + + /** + * Collection of artifact definitions to exclude. The {@link Exclude} + * element defines a {@code groupId} and {@code artifactId} mandatory + * properties and an optional {@code classifier} property. + * @since 1.1 + */ + @Parameter + private List excludes; + + /** + * Comma separated list of groupId names to exclude. + * @since 1.1 + */ + @Parameter(property = "excludeGroupIds", defaultValue = "") + protected String excludeGroupIds; + + /** + * Comma separated list of artifact names to exclude. + * @since 1.1 + */ + @Parameter(property = "excludeArtifactIds", defaultValue = "") + protected String excludeArtifactIds; + + + protected void setExcludes(List excludes) { + this.excludes = excludes; + } + + protected void setExcludeGroupIds(String excludeGroupIds) { + this.excludeGroupIds = excludeGroupIds; + } + + protected void setExcludeArtifactIds(String excludeArtifactIds) { + this.excludeArtifactIds = excludeArtifactIds; + } + + @SuppressWarnings("unchecked") + protected Set filterDependencies(Set dependencies, FilterArtifacts filters) + throws MojoExecutionException { + try { + return filters.filter(dependencies); + } + catch (ArtifactFilterException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } + + protected void initializeFilterArtifacts(FilterArtifacts filters) { + filters.addFilter(new ArtifactIdFilter("", cleanConfigItem(this.excludeArtifactIds))); + filters.addFilter(new GroupIdFilter("", cleanConfigItem(this.excludeGroupIds))); + if (this.excludes != null) { + filters.addFilter(new ExcludeFilter(this.excludes)); + } + } + + + static String cleanConfigItem(String content) { + if (content == null || content.trim().isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + StringTokenizer st = new StringTokenizer(content, ","); + while (st.hasMoreElements()) { + String t = st.nextToken(); + sb.append(t.trim()); + if (st.hasMoreElements()) { + sb.append(","); + } + } + return sb.toString(); + } +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java new file mode 100644 index 00000000000..26642e41686 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2014 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 + * + * http://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 org.apache.maven.plugins.annotations.Parameter; + +/** + * A model for a dependency to exclude. + * + * @author Stephane Nicoll + * @since 1.1 + */ +public class Exclude { + + /** + * The groupId of the artifact to exclude. + */ + @Parameter(required = true) + private String groupId; + + /** + * The artifactId of the artifact to exclude. + */ + @Parameter(required = true) + private String artifactId; + + /** + * The classifier of the artifact to exclude + */ + @Parameter + private String classifier; + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public void setArtifactId(String artifactId) { + this.artifactId = artifactId; + } + + public String getClassifier() { + return classifier; + } + + public void setClassifier(String classifier) { + this.classifier = classifier; + } +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ExcludeFilter.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ExcludeFilter.java new file mode 100644 index 00000000000..523995346b0 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ExcludeFilter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2014 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 + * + * http://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.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter; +import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException; + +/** + * An {@link org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter + * ArtifactsFilter} that filters out any artifact matching a configurable list + * of {@link Exclude} instances. + * + * @author Stephane Nicoll + * @since 1.1 + */ +public class ExcludeFilter extends AbstractArtifactsFilter{ + + private final List excludes; + + /** + * Create a new instance with the list of {@link Exclude} + * instance(s) to use. + */ + public ExcludeFilter(List excludes) { + this.excludes = excludes; + } + + @Override + public Set filter(Set artifacts) throws ArtifactFilterException { + Set result = new HashSet(); + for (Object a : artifacts) { + Artifact artifact = (Artifact) a; + if (!matchExclude(artifact)) { + result.add(artifact); + } + } + return result; + } + + /** + * Check if the specified {@link Artifact} matches one of the + * known excludes. Returns {@code true} if it should be excluded + */ + private boolean matchExclude(Artifact artifact) { + for (Exclude exclude : excludes) { + if (match(artifact, exclude)) { + return true; + } + } + return false; + } + + /** + * Check if the specified {@link Artifact} matches the specified + * {@link Exclude}. Returns {@code true} if it should be excluded + */ + private boolean match(Artifact artifact, Exclude exclude) { + if (!exclude.getGroupId().equals(artifact.getGroupId())) { + return false; + } + if (!exclude.getArtifactId().equals(artifact.getArtifactId())) { + return false; + } + return exclude.getClassifier() == null || + artifact.getClassifier() != null && exclude.getClassifier().equals(artifact.getClassifier()); + + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index c008a28b30a..fee277d1a26 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -18,9 +18,11 @@ package org.springframework.boot.maven; import java.io.File; import java.io.IOException; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.jar.JarFile; +import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -31,6 +33,8 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; +import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; + import org.springframework.boot.loader.tools.Layout; import org.springframework.boot.loader.tools.Layouts; import org.springframework.boot.loader.tools.Libraries; @@ -46,7 +50,7 @@ import org.springframework.boot.loader.tools.Repackager; * @author Stephane Nicoll */ @Mojo(name = "repackage", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME) -public class RepackageMojo extends AbstractMojo { +public class RepackageMojo extends AbstractDependencyFilterMojo { private static final long FIND_WARNING_TIMEOUT = TimeUnit.SECONDS.toMillis(10); @@ -134,7 +138,12 @@ public class RepackageMojo extends AbstractMojo { getLog().info("Layout: " + this.layout); repackager.setLayout(this.layout.layout()); } - Libraries libraries = new ArtifactsLibraries(this.project.getArtifacts()); + + FilterArtifacts filters = new FilterArtifacts(); + initializeFilterArtifacts(filters); + Set artifacts = filterDependencies(this.project.getArtifacts(), filters); + + Libraries libraries = new ArtifactsLibraries(artifacts); try { repackager.repackage(target, libraries); } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 434a44a8820..6ea9857454a 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -24,10 +24,10 @@ import java.security.CodeSource; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Execute; @@ -36,6 +36,9 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter; +import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; + import org.springframework.boot.loader.tools.FileUtils; import org.springframework.boot.loader.tools.JavaExecutable; import org.springframework.boot.loader.tools.MainClassFinder; @@ -43,13 +46,13 @@ import org.springframework.boot.loader.tools.RunProcess; /** * Run an executable archive application. - * + * * @author Phillip Webb * @author Stephane Nicoll */ @Mojo(name = "run", requiresProject = true, defaultPhase = LifecyclePhase.VALIDATE, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) -public class RunMojo extends AbstractMojo { +public class RunMojo extends AbstractDependencyFilterMojo { private static final String SPRING_LOADED_AGENT_CLASSNAME = "org.springsource.loaded.agent.SpringLoadedAgent"; @@ -253,14 +256,27 @@ public class RunMojo extends AbstractMojo { urls.add(this.classesDirectory.toURI().toURL()); } - private void addDependencies(List urls) throws MalformedURLException { - for (Artifact artifact : this.project.getArtifacts()) { + private void addDependencies(List urls) throws MalformedURLException, MojoExecutionException { + FilterArtifacts filters = new FilterArtifacts(); + filters.addFilter(new TestArtifactFilter()); + initializeFilterArtifacts(filters); + + Set artifacts = filterDependencies(this.project.getArtifacts(), filters); + for (Artifact artifact : artifacts) { if (artifact.getFile() != null) { - if (!Artifact.SCOPE_TEST.equals(artifact.getScope())) { - urls.add(artifact.getFile().toURI().toURL()); - } + urls.add(artifact.getFile().toURI().toURL()); } } } + private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { + public TestArtifactFilter() { + super("", Artifact.SCOPE_TEST); + } + + protected String getArtifactFeature(Artifact artifact) { + return artifact.getScope(); + } + } + } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/exclude-dependency.apt.vm b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/exclude-dependency.apt.vm new file mode 100644 index 00000000000..77985559ed3 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/exclude-dependency.apt.vm @@ -0,0 +1,117 @@ + ----- + Exclude a dependency + ----- + Stephane Nicoll + ----- + 2014-05-06 + ----- + + By default, both the <<>> and the <<>> goals will include any <<>> + dependencies that are defined in the project. A boot-based project should consider + <<>> dependencies as <> dependencies that are required to run + the application. + + Some of these dependencies may not be required at all and should be excluded from the + executable jar. For consistency, they should not be present either when running the + application. + + There are tree ways one can exclude a dependency from being packaged/used at runtime + + * Exclude a specific artifact identified by <<>> and <<>> + (optionnaly with a <<>> if needed) + + * Exclude any artifact matching a given <<>> + + * Exclude any artifact belonging to a given <<>> + + [] + + The following excludes <<>> (and only that artifact) + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + com.foo + bar + + + + ... + + ... + + ... + + ... + +--- + + This example excludes every artifacts having the <<>> or <<>> + artifact identifiers + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + my-lib,another-lib + + + ... + + ... + + ... + + ... + +--- + + Finally this example excludes any artifact belonging to the <<>> group + + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + com.foo + + + ... + + ... + + ... + + ... + +--- + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm similarity index 100% rename from spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt rename to spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index c820748c17c..b7f2e3f4128 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -38,6 +38,8 @@ Spring Boot Maven Plugin * {{{./examples/repackage-classifier.html}Custom repackage classifier}} + * {{{./examples/exclude-dependency.html}Exclude a dependency}} + [] diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index 7b3e5c0d481..9afbd2544e2 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -4,7 +4,7 @@ ----- Stephane Nicoll ----- - 2014-05-02 + 2014-05-06 ----- Usage @@ -40,9 +40,13 @@ Usage --- - The example above repackages a jar or war that is built during the package phase of the Maven lifecycle. The - original (i.e. non exectuable) artifact is renamed to <<<.original>>> by default but it is also possible to - keep the original artifact using a custom classifier. + The example above repackages a jar or war that is built during the package phase of the Maven lifecycle, + including any <<>> dependencies that are defined in the project. If some of these dependencies + need to be excluded, you can use one of the exclude options, + see {{{./examples/exclude-dependency.html}Exclude a dependency}} for more details. + + The original (i.e. non exectuable) artifact is renamed to <<<.original>>> by default but it is also + possible to keep the original artifact using a custom classifier. The plugin rewrites your manifest, and in particular it manages the <> and <> entries, so if the defaults don't work you have to configure those there (not in the jar plugin). The @@ -82,6 +86,8 @@ Usage * {{{./examples/repackage-classifier.html}Custom repackage classifier}} + * {{{./examples/exclude-dependency.html}Exclude a dependency}} + [] * Running the application @@ -120,4 +126,9 @@ mvn spring-boot:run ... ---- \ No newline at end of file +--- + + In order to be consistent with the <<>> goal, the <<>> goal builds the classpath + in such a way that any dependency that is excluded in the plugin's configuration gets excluded + from the classpath as well. See {{{./examples/exclude-dependency.html}Exclude a dependency}} for + more details. \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index 73c82ec3067..93cddec5b74 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -8,6 +8,7 @@ + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java new file mode 100644 index 00000000000..bbbad742d8a --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2014 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 + * + * http://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 static org.junit.Assert.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; +import org.junit.Test; + +/** + * + * @author Stephane Nicoll + */ +public class DependencyFilterMojoTests { + + @Test + public void filterDependencies() throws MojoExecutionException { + TestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo( + Collections.emptyList(), "com.foo", "exclude-id"); + + Artifact artifact = createArtifact("com.bar", "one"); + Set artifacts = mojo.filterDependencies(createArtifact("com.foo", "one"), + createArtifact("com.foo", "two"), + createArtifact("com.bar", "exclude-id"), + artifact); + assertEquals("wrong filtering of artifacts", 1, artifacts.size()); + assertSame("Wrong filtered artifact", artifact, artifacts.iterator().next()); + } + + + + private Artifact createArtifact(String groupId, String artifactId) { + Artifact a = mock(Artifact.class); + given(a.getGroupId()).willReturn(groupId); + given(a.getArtifactId()).willReturn(artifactId); + return a; + } + + + private static class TestableDependencyFilterMojo extends AbstractDependencyFilterMojo { + + private TestableDependencyFilterMojo(List excludes, String excludeGroupIds, String excludeArtifactIds) { + setExcludes(excludes); + setExcludeGroupIds(excludeGroupIds); + setExcludeArtifactIds(excludeArtifactIds); + } + + public Set filterDependencies(Artifact... artifacts) throws MojoExecutionException { + Set input = new HashSet(Arrays.asList(artifacts)); + FilterArtifacts filters = new FilterArtifacts(); + initializeFilterArtifacts(filters); + return filterDependencies(input, filters); + } + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + } + } +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ExcludeFilterTests.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ExcludeFilterTests.java new file mode 100644 index 00000000000..ed1da0f6e03 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ExcludeFilterTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 2012-2014 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 + * + * http://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 static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException; +import org.junit.Test; + +/** + * + * @author Stephane Nicoll + */ +public class ExcludeFilterTests { + + + @Test + public void excludeSimple() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar"))); + Set result = filter.filter(Collections.singleton(createArtifact("com.foo", "bar"))); + assertEquals("Should have been filtered", 0, result.size()); + } + + @Test + public void excludeGroupIdNoMatch() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar"))); + Artifact artifact = createArtifact("com.baz", "bar"); + Set result = filter.filter(Collections.singleton(artifact)); + assertEquals("Should not have been filtered", 1, result.size()); + assertSame(artifact, result.iterator().next()); + } + + @Test + public void excludeArtifactIdNoMatch() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar"))); + Artifact artifact = createArtifact("com.foo", "biz"); + Set result = filter.filter(Collections.singleton(artifact)); + assertEquals("Should not have been filtered", 1, result.size()); + assertSame(artifact, result.iterator().next()); + } + + @Test + public void excludeClassifier() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar", "jdk5"))); + Set result = filter.filter(Collections.singleton(createArtifact("com.foo", "bar", "jdk5"))); + assertEquals("Should have been filtered", 0, result.size()); + } + + @Test + public void excludeClassifierNoTargetClassifier() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar", "jdk5"))); + Artifact artifact = createArtifact("com.foo", "bar"); + Set result = filter.filter(Collections.singleton(artifact)); + assertEquals("Should not have been filtered", 1, result.size()); + assertSame(artifact, result.iterator().next()); + } + + @Test + public void excludeClassifierNoMatch() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude("com.foo", "bar", "jdk5"))); + Artifact artifact = createArtifact("com.foo", "bar", "jdk6"); + Set result = filter.filter(Collections.singleton(artifact)); + assertEquals("Should not have been filtered", 1, result.size()); + assertSame(artifact, result.iterator().next()); + } + + @Test + public void excludeMulti() throws ArtifactFilterException { + ExcludeFilter filter = new ExcludeFilter(Arrays.asList( + createExclude("com.foo", "bar"), + createExclude("com.foo", "bar2"), + createExclude("org.acme", "app"))); + Set artifacts = new HashSet(); + artifacts.add(createArtifact("com.foo", "bar")); + artifacts.add(createArtifact("com.foo", "bar")); + Artifact anotherAcme = createArtifact("org.acme", "another-app"); + artifacts.add(anotherAcme); + Set result = filter.filter(artifacts); + assertEquals("Two dependencies should have been filtered", 1, result.size()); + assertSame(anotherAcme, result.iterator().next()); + } + + + private Exclude createExclude(String groupId, String artifactId, String classifier) { + Exclude e = new Exclude(); + e.setGroupId(groupId); + e.setArtifactId(artifactId); + if (classifier != null) { + e.setClassifier(classifier); + } + return e; + } + + private Exclude createExclude(String groupId, String artifactId) { + return createExclude(groupId, artifactId, null); + } + + private Artifact createArtifact(String groupId, String artifactId, String classifier) { + Artifact a = mock(Artifact.class); + given(a.getGroupId()).willReturn(groupId); + given(a.getArtifactId()).willReturn(artifactId); + given(a.getClassifier()).willReturn(classifier); + return a; + } + + private Artifact createArtifact(String groupId, String artifactId) { + return createArtifact(groupId, artifactId, null); + } +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/RepackageMojoTests.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/RepackageMojoTests.java new file mode 100644 index 00000000000..1ce9810653f --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/RepackageMojoTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2014 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 + * + * http://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 static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** + * + * @author Stephane Nicoll + */ +public class RepackageMojoTests { + + + @Test + public void cleanConfigItemWithSpaces() { + assertEquals("foo,bar,biz", RepackageMojo.cleanConfigItem("foo, bar , biz")); + } + + @Test + public void cleanNullConfigItemWith() { + assertEquals("", RepackageMojo.cleanConfigItem(null)); + } + + @Test + public void cleanEmptyConfigItemWith() { + assertEquals("", RepackageMojo.cleanConfigItem("")); + } +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java index 84a3ff75e29..ebd4f7461b5 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java @@ -17,6 +17,8 @@ package org.springframework.boot.maven; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -34,8 +36,10 @@ import static org.junit.Assert.assertTrue; */ public class Verify { + public static final String SAMPLE_APP = "org.test.SampleApplication"; + public static void verifyJar(File file) throws Exception { - new JarArchiveVerification(file, "org.test.SampleApplication").verify(); + new JarArchiveVerification(file, SAMPLE_APP).verify(); } public static void verifyJar(File file, String main) throws Exception { @@ -50,6 +54,57 @@ public class Verify { new ZipArchiveVerification(file).verify(); } + public static class ArchiveVerifier { + + private final ZipFile zipFile; + private final Map content; + + public ArchiveVerifier(ZipFile zipFile) { + this.zipFile = zipFile; + Enumeration entries = zipFile.entries(); + this.content = new HashMap(); + while (entries.hasMoreElements()) { + ZipEntry zipEntry = entries.nextElement(); + this.content.put(zipEntry.getName(), zipEntry); + } + } + + public void assertHasEntryNameStartingWith(String entry) { + for (String name : this.content.keySet()) { + if (name.startsWith(entry)) { + return; + } + } + throw new IllegalStateException("Expected entry starting with " + entry); + } + + public void assertHasNoEntryNameStartingWith(String entry) { + for (String name : this.content.keySet()) { + if (name.startsWith(entry)) { + throw new IllegalStateException("Entry starting with " + + entry + " should not have been found"); + } + } + } + + public boolean hasEntry(String entry) { + return this.content.containsKey(entry); + } + + public ZipEntry getEntry(String entry) { + return this.content.get(entry); + } + + public InputStream getEntryContent(String entry) throws IOException { + ZipEntry zipEntry = getEntry(entry); + if (zipEntry == null) { + throw new IllegalArgumentException("No entry with name ["+entry+"]"); + } + return this.zipFile.getInputStream(zipEntry); + } + + } + private static abstract class AbstractArchiveVerification { private final File file; @@ -63,40 +118,30 @@ public class Verify { assertTrue("Archive not a file", this.file.isFile()); ZipFile zipFile = new ZipFile(this.file); - Enumeration entries = zipFile.entries(); - Map zipMap = new HashMap(); - while (entries.hasMoreElements()) { - ZipEntry zipEntry = entries.nextElement(); - zipMap.put(zipEntry.getName(), zipEntry); + try { + ArchiveVerifier verifier = new ArchiveVerifier(zipFile); + verifyZipEntries(verifier); + } + finally { + zipFile.close(); } - verifyZipEntries(zipFile, zipMap); - zipFile.close(); } - protected void verifyZipEntries(ZipFile zipFile, Map entries) + protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { - verifyManifest(zipFile, entries.get("META-INF/MANIFEST.MF")); + verifyManifest(verifier); } - private void verifyManifest(ZipFile zipFile, ZipEntry zipEntry) throws Exception { - Manifest manifest = new Manifest(zipFile.getInputStream(zipEntry)); + private void verifyManifest(ArchiveVerifier verifier) throws Exception { + Manifest manifest = new Manifest(verifier.getEntryContent("META-INF/MANIFEST.MF")); verifyManifest(manifest); } protected abstract void verifyManifest(Manifest manifest) throws Exception; - protected final void assertHasEntryNameStartingWith( - Map entries, String value) { - for (String name : entries.keySet()) { - if (name.startsWith(value)) { - return; - } - } - throw new IllegalStateException("Expected entry starting with " + value); - } } - private static class JarArchiveVerification extends AbstractArchiveVerification { + public static class JarArchiveVerification extends AbstractArchiveVerification { private final String main; @@ -106,15 +151,15 @@ public class Verify { } @Override - protected void verifyZipEntries(ZipFile zipFile, Map entries) + protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { - super.verifyZipEntries(zipFile, entries); - assertHasEntryNameStartingWith(entries, "lib/spring-context"); - assertHasEntryNameStartingWith(entries, "lib/spring-core"); - assertHasEntryNameStartingWith(entries, "lib/javax.servlet-api-3.0.1.jar"); - assertTrue("Unpacked launcher classes", entries.containsKey("org/" + super.verifyZipEntries(verifier); + verifier.assertHasEntryNameStartingWith("lib/spring-context"); + verifier.assertHasEntryNameStartingWith("lib/spring-core"); + verifier.assertHasEntryNameStartingWith("lib/javax.servlet-api-3.0.1.jar"); + assertTrue("Unpacked launcher classes", verifier.hasEntry("org/" + "springframework/boot/loader/JarLauncher.class")); - assertTrue("Own classes", entries.containsKey("org/" + assertTrue("Own classes", verifier.hasEntry("org/" + "test/SampleApplication.class")); } @@ -127,25 +172,25 @@ public class Verify { } } - private static class WarArchiveVerification extends AbstractArchiveVerification { + public static class WarArchiveVerification extends AbstractArchiveVerification { public WarArchiveVerification(File file) { super(file); } @Override - protected void verifyZipEntries(ZipFile zipFile, Map entries) + protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { - super.verifyZipEntries(zipFile, entries); - assertHasEntryNameStartingWith(entries, "WEB-INF/lib/spring-context"); - assertHasEntryNameStartingWith(entries, "WEB-INF/lib/spring-core"); - assertHasEntryNameStartingWith(entries, + super.verifyZipEntries(verifier); + verifier.assertHasEntryNameStartingWith("WEB-INF/lib/spring-context"); + verifier.assertHasEntryNameStartingWith("WEB-INF/lib/spring-core"); + verifier.assertHasEntryNameStartingWith( "WEB-INF/lib-provided/javax.servlet-api-3.0.1.jar"); - assertTrue("Unpacked launcher classes", entries.containsKey("org/" + assertTrue("Unpacked launcher classes", verifier.hasEntry("org/" + "springframework/boot/loader/JarLauncher.class")); - assertTrue("Own classes", entries.containsKey("WEB-INF/classes/org/" + assertTrue("Own classes", verifier.hasEntry("WEB-INF/classes/org/" + "test/SampleApplication.class")); - assertTrue("Web content", entries.containsKey("index.html")); + assertTrue("Web content", verifier.hasEntry("index.html")); } @Override