Commit c51d836a authored by Stephane Nicoll's avatar Stephane Nicoll

Use standard file name for Maven dependencies

This commit uses standard files for libraries managed by the repackage
goal of the Maven plugin. Previously, only the name of the file was used
which could lead to duplicate libraries if the name of the target file
deviates from the default. This typically happens when the
`build.finalName` property is specified on a dependent module.

Note that the `maven-war-plugin` has an additional mechanism to customize
the file name structure of dependencies. This feature isn't supported by
the repackage goal so an explicit mention has been added in the
documentation.

Closes gh-7389
parent e5ca4990
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>war-reactor</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>jar</artifactId>
<packaging>jar</packaging>
<name>jar</name>
<description>Jar dependency</description>
<build>
<finalName>jar</finalName>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>war-reactor</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>jar</module>
<module>war</module>
</modules>
</project>
/*
* Copyright 2012-2015 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, "war/target/war-0.0.1.BUILD-SNAPSHOT.war")
new Verify.WarArchiveVerification(f) {
@Override
protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception {
super.verifyZipEntries(verifier)
verifier.assertHasEntryNameStartingWith("WEB-INF/lib/jar-0.0.1.BUILD-SNAPSHOT.jar")
verifier.assertHasNoEntryNameStartingWith("WEB-INF/lib/jar.jar")
}
}.verify()
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>war-reactor</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>war</artifactId>
<packaging>war</packaging>
<name>war</name>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifestEntries>
<Not-Used>Foo</Not-Used>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>@spring.version@</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>@servlet-api.version@</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
/*
* 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.test;
public class SampleApplication {
public static void main(String[] args) {
}
}
...@@ -38,6 +38,7 @@ import org.springframework.boot.loader.tools.LibraryScope; ...@@ -38,6 +38,7 @@ import org.springframework.boot.loader.tools.LibraryScope;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll
*/ */
public class ArtifactsLibraries implements Libraries { public class ArtifactsLibraries implements Libraries {
...@@ -71,7 +72,7 @@ public class ArtifactsLibraries implements Libraries { ...@@ -71,7 +72,7 @@ public class ArtifactsLibraries implements Libraries {
for (Artifact artifact : this.artifacts) { for (Artifact artifact : this.artifacts) {
LibraryScope scope = SCOPES.get(artifact.getScope()); LibraryScope scope = SCOPES.get(artifact.getScope());
if (scope != null && artifact.getFile() != null) { if (scope != null && artifact.getFile() != null) {
String name = artifact.getFile().getName(); String name = getFileName(artifact);
if (duplicates.contains(name)) { if (duplicates.contains(name)) {
this.log.debug("Duplicate found: " + name); this.log.debug("Duplicate found: " + name);
name = artifact.getGroupId() + "-" + name; name = artifact.getGroupId() + "-" + name;
...@@ -87,8 +88,9 @@ public class ArtifactsLibraries implements Libraries { ...@@ -87,8 +88,9 @@ public class ArtifactsLibraries implements Libraries {
Set<String> duplicates = new HashSet<String>(); Set<String> duplicates = new HashSet<String>();
Set<String> seen = new HashSet<String>(); Set<String> seen = new HashSet<String>();
for (Artifact artifact : artifacts) { for (Artifact artifact : artifacts) {
if (artifact.getFile() != null && !seen.add(artifact.getFile().getName())) { String fileName = getFileName(artifact);
duplicates.add(artifact.getFile().getName()); if (artifact.getFile() != null && !seen.add(fileName)) {
duplicates.add(fileName);
} }
} }
return duplicates; return duplicates;
...@@ -106,4 +108,15 @@ public class ArtifactsLibraries implements Libraries { ...@@ -106,4 +108,15 @@ public class ArtifactsLibraries implements Libraries {
return false; return false;
} }
private String getFileName(Artifact artifact) {
StringBuilder sb = new StringBuilder();
sb.append(artifact.getArtifactId()).append("-").append(artifact.getVersion());
String classifier = artifact.getClassifier();
if (classifier != null) {
sb.append("-").append(classifier);
}
sb.append(".").append(artifact.getArtifactHandler().getExtension());
return sb.toString();
}
} }
...@@ -57,6 +57,8 @@ Usage ...@@ -57,6 +57,8 @@ Usage
including any <<<provided>>> dependencies that are defined in the project. If some of these dependencies including any <<<provided>>> dependencies that are defined in the project. If some of these dependencies
need to be excluded, you can use one of the exclude options, need to be excluded, you can use one of the exclude options,
see {{{./examples/exclude-dependency.html}Exclude a dependency}} for more details. see {{{./examples/exclude-dependency.html}Exclude a dependency}} for more details.
Please note that the <<<outputFileNameMapping>>> feature of the <<<maven-war-plugin>>>
is currently not supported.
The original (i.e. non executable) artifact is renamed to <<<.original>>> by default but it is also The original (i.e. non executable) artifact is renamed to <<<.original>>> by default but it is also
possible to keep the original artifact using a custom classifier. possible to keep the original artifact using a custom classifier.
......
...@@ -23,6 +23,7 @@ import java.util.LinkedHashSet; ...@@ -23,6 +23,7 @@ import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.model.Dependency; import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugin.logging.Log;
import org.junit.Before; import org.junit.Before;
...@@ -52,6 +53,9 @@ public class ArtifactsLibrariesTests { ...@@ -52,6 +53,9 @@ public class ArtifactsLibrariesTests {
@Mock @Mock
private Artifact artifact; private Artifact artifact;
@Mock
private ArtifactHandler artifactHandler;
private Set<Artifact> artifacts; private Set<Artifact> artifacts;
private File file = new File("."); private File file = new File(".");
...@@ -70,6 +74,8 @@ public class ArtifactsLibrariesTests { ...@@ -70,6 +74,8 @@ public class ArtifactsLibrariesTests {
this.artifacts = Collections.singleton(this.artifact); this.artifacts = Collections.singleton(this.artifact);
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class)); this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
given(this.artifact.getFile()).willReturn(this.file); given(this.artifact.getFile()).willReturn(this.file);
given(this.artifactHandler.getExtension()).willReturn("jar");
given(this.artifact.getArtifactHandler()).willReturn(this.artifactHandler);
} }
@Test @Test
...@@ -107,17 +113,25 @@ public class ArtifactsLibrariesTests { ...@@ -107,17 +113,25 @@ public class ArtifactsLibrariesTests {
given(artifact1.getType()).willReturn("jar"); given(artifact1.getType()).willReturn("jar");
given(artifact1.getScope()).willReturn("compile"); given(artifact1.getScope()).willReturn("compile");
given(artifact1.getGroupId()).willReturn("g1"); given(artifact1.getGroupId()).willReturn("g1");
given(artifact1.getArtifactId()).willReturn("artifact");
given(artifact1.getVersion()).willReturn("1.0");
given(artifact1.getFile()).willReturn(new File("a")); given(artifact1.getFile()).willReturn(new File("a"));
given(artifact1.getArtifactHandler()).willReturn(this.artifactHandler);
given(artifact2.getType()).willReturn("jar"); given(artifact2.getType()).willReturn("jar");
given(artifact2.getScope()).willReturn("compile"); given(artifact2.getScope()).willReturn("compile");
given(artifact2.getGroupId()).willReturn("g2"); given(artifact2.getGroupId()).willReturn("g2");
given(artifact2.getArtifactId()).willReturn("artifact");
given(artifact2.getVersion()).willReturn("1.0");
given(artifact2.getFile()).willReturn(new File("a")); given(artifact2.getFile()).willReturn(new File("a"));
given(artifact2.getArtifactHandler()).willReturn(this.artifactHandler);
this.artifacts = new LinkedHashSet<Artifact>(Arrays.asList(artifact1, artifact2)); this.artifacts = new LinkedHashSet<Artifact>(Arrays.asList(artifact1, artifact2));
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class)); this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
this.libs.doWithLibraries(this.callback); this.libs.doWithLibraries(this.callback);
verify(this.callback, times(2)).library(this.libraryCaptor.capture()); verify(this.callback, times(2)).library(this.libraryCaptor.capture());
assertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo("g1-a"); assertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo(
assertThat(this.libraryCaptor.getAllValues().get(1).getName()).isEqualTo("g2-a"); "g1-artifact-1.0.jar");
assertThat(this.libraryCaptor.getAllValues().get(1).getName()).isEqualTo(
"g2-artifact-1.0.jar");
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment