容器描述符处理程序可用于动态过滤描述符中配置的文件的内容,例如通过将多个文件聚合到单个文件中,或自定义特定文件的内容。
此示例演示了在程序集描述符格式中<containerDescriptorHandlers>的使用。
该插件附带了几个已经定义的处理程序。
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
....
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>file-aggregator</handlerName>
<configuration>
<filePattern>.*/file.txt</filePattern>
<outputPath>file.txt</outputPath>
</configuration>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
....
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>metaInf-services</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
....
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>metaInf-spring</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
....
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>plexus</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
您可以通过创建实现ContainerDescriptorHandler的类来创建自己的容器描述符处理程序。例如,让我们创建一个处理程序,它将配置的注释添加到程序集描述符中配置的每个属性文件中。
我们首先使用以下 POM创建一个名为custom-container-descriptor-handler的新 Maven 项目:
<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>com.test</groupId>
<artifactId>custom-container-descriptor-handler</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<version>1.7.1</version>
<executions>
<execution>
<goals>
<goal>generate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
这个 POM 声明了对 Assembly Plugin 的依赖,以便我们可以创建我们的处理程序,并生成一个 Plexus 配置文件,以便在组装过程中通过依赖注入找到它。
实现ContainerDescriptorHandler需要定义几个方法:
我们为每个属性文件添加注释的处理程序可能如下所示(此处使用 Java 8 特性):
package com.test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.maven.plugins.assembly.filter.ContainerDescriptorHandler;
import org.apache.maven.plugins.assembly.utils.AssemblyFileUtils;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.components.io.fileselectors.FileInfo;
@Component(role = ContainerDescriptorHandler.class, hint = "custom")
public class MyCustomDescriptorHandler implements ContainerDescriptorHandler {
private String comment;
private Map<String, List<String>> catalog = new HashMap<>();
private boolean excludeOverride = false;
@Override
public void finalizeArchiveCreation(Archiver archiver) throws ArchiverException {
archiver.getResources().forEachRemaining(a -> {}); // necessary to prompt the isSelected() call
for (Map.Entry<String, List<String>> entry : catalog.entrySet())
{
String name = entry.getKey();
String fname = new File(name).getName();
Path p;
try {
p = Files.createTempFile("assembly-" + fname, ".tmp");
} catch (IOException e) {
throw new ArchiverException("Cannot create temporary file to finalize archive creation", e);
}
try (BufferedWriter writer = Files.newBufferedWriter(p, StandardCharsets.ISO_8859_1)) {
writer.write("# " + comment);
for (String line : entry.getValue()) {
writer.newLine();
writer.write(line);
}
} catch (IOException e) {
throw new ArchiverException("Error adding content of " + fname + " to finalize archive creation", e);
}
File file = p.toFile();
file.deleteOnExit();
excludeOverride = true;
archiver.addFile(file, name);
excludeOverride = false;
}
}
@Override
public void finalizeArchiveExtraction(UnArchiver unarchiver) throws ArchiverException { }
@Override
public List<String> getVirtualFiles() {
return new ArrayList<>(catalog.keySet());
}
@Override
public boolean isSelected(FileInfo fileInfo) throws IOException {
if (excludeOverride) {
return true;
}
String name = AssemblyFileUtils.normalizeFileInfo(fileInfo);
if (fileInfo.isFile() && AssemblyFileUtils.isPropertyFile(name)) {
catalog.put(name, readLines(fileInfo));
return false;
}
return true;
}
private List<String> readLines(FileInfo fileInfo) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fileInfo.getContents(), StandardCharsets.ISO_8859_1))) {
return reader.lines().collect(Collectors.toList());
}
}
public void setComment(String comment) {
this.comment = comment;
}
}
它是一个 Plexus 组件,具有ContainerDescriptorHandler角色,通过它的custom提示与其他处理程序区分开来。
它选择每个属性文件并将其内容存储到目录映射中,其中键是文件的名称,值是其行的列表。那些匹配的文件不会添加到程序集中,因为处理程序需要先处理它们。在程序集创建期间,它会创建临时文件,其内容是先前读取的行,前面有自定义注释。然后,它们会以其以前的名称重新添加到存档中。请注意,这个简单的处理程序不会聚合具有相同名称的文件 - 可以对其进行增强。将临时文件添加到存档时,会自动调用isSelected方法,因此我们需要将布尔excludeOverride设置为true以确保目录处理部分未完成。
最后一个要素是在某个 Maven 项目的程序集描述符中使用我们的自定义处理程序。假设该项目中有一个src/samples目录,其中包含一个名为test.xml的 XML 文件和一个名为test.properties的属性文件。具有以下描述符格式
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>dist</id>
<formats>
<format>zip</format>
</formats>
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>custom</handlerName>
<configuration>
<comment>A comment</comment>
</configuration>
</containerDescriptorHandler>
</containerDescriptorHandlers>
<fileSets>
<fileSet>
<directory>src/samples</directory>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
</assembly>
以及以下 Assembly 插件配置
<project>
[...]
<build>
[...]
<plugins>
[...]
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assemble/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>custom-container-descriptor-handler</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
[...]
</project>
生成的程序集将包含基本目录下的test.xml和test.properties,只有后者以#A注释开头。