容器描述符处理程序可用于动态过滤描述符中配置的文件的内容,例如通过将多个文件聚合到单个文件中,或自定义特定文件的内容。
此示例演示了在程序集描述符格式中<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注释开头。