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
This commit is contained in:
Stephane Nicoll 2016-11-28 17:41:10 +01:00
parent e5ca4990d0
commit c51d836a15
9 changed files with 183 additions and 5 deletions

View File

@ -0,0 +1,18 @@
<?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>

View File

@ -0,0 +1,16 @@
<?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>

View File

@ -0,0 +1,29 @@
/*
* 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()

View File

@ -0,0 +1,61 @@
<?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>

View File

@ -0,0 +1,24 @@
/*
* 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) {
}
}

View File

@ -38,6 +38,7 @@ import org.springframework.boot.loader.tools.LibraryScope;
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class ArtifactsLibraries implements Libraries {
@ -71,7 +72,7 @@ public class ArtifactsLibraries implements Libraries {
for (Artifact artifact : this.artifacts) {
LibraryScope scope = SCOPES.get(artifact.getScope());
if (scope != null && artifact.getFile() != null) {
String name = artifact.getFile().getName();
String name = getFileName(artifact);
if (duplicates.contains(name)) {
this.log.debug("Duplicate found: " + name);
name = artifact.getGroupId() + "-" + name;
@ -87,8 +88,9 @@ public class ArtifactsLibraries implements Libraries {
Set<String> duplicates = new HashSet<String>();
Set<String> seen = new HashSet<String>();
for (Artifact artifact : artifacts) {
if (artifact.getFile() != null && !seen.add(artifact.getFile().getName())) {
duplicates.add(artifact.getFile().getName());
String fileName = getFileName(artifact);
if (artifact.getFile() != null && !seen.add(fileName)) {
duplicates.add(fileName);
}
}
return duplicates;
@ -106,4 +108,15 @@ public class ArtifactsLibraries implements Libraries {
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();
}
}

View File

@ -57,6 +57,8 @@ Usage
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,
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
possible to keep the original artifact using a custom classifier.

View File

@ -23,6 +23,7 @@ import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.logging.Log;
import org.junit.Before;
@ -52,6 +53,9 @@ public class ArtifactsLibrariesTests {
@Mock
private Artifact artifact;
@Mock
private ArtifactHandler artifactHandler;
private Set<Artifact> artifacts;
private File file = new File(".");
@ -70,6 +74,8 @@ public class ArtifactsLibrariesTests {
this.artifacts = Collections.singleton(this.artifact);
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
given(this.artifact.getFile()).willReturn(this.file);
given(this.artifactHandler.getExtension()).willReturn("jar");
given(this.artifact.getArtifactHandler()).willReturn(this.artifactHandler);
}
@Test
@ -107,17 +113,25 @@ public class ArtifactsLibrariesTests {
given(artifact1.getType()).willReturn("jar");
given(artifact1.getScope()).willReturn("compile");
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.getArtifactHandler()).willReturn(this.artifactHandler);
given(artifact2.getType()).willReturn("jar");
given(artifact2.getScope()).willReturn("compile");
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.getArtifactHandler()).willReturn(this.artifactHandler);
this.artifacts = new LinkedHashSet<Artifact>(Arrays.asList(artifact1, artifact2));
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
this.libs.doWithLibraries(this.callback);
verify(this.callback, times(2)).library(this.libraryCaptor.capture());
assertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo("g1-a");
assertThat(this.libraryCaptor.getAllValues().get(1).getName()).isEqualTo("g2-a");
assertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo(
"g1-artifact-1.0.jar");
assertThat(this.libraryCaptor.getAllValues().get(1).getName()).isEqualTo(
"g2-artifact-1.0.jar");
}
}