maven 自定义插件小示例
程序员文章站
2022-04-30 18:12:54
...
maven作为一个核心是插件的架构,所有的工作都通过插件来执行,主要分为两类build和report
maven官方已经给我们提供了各种各样的插件maven plugins,但有时我们还是需要自己定义我们特殊的插件,比如我们项目中根据特定的文件,自动生成对应的java类,这时就需要我们实现自己的特定插件了,本示例包含两个工程,
为了使示例保持简单,插件工程只演示了从特定目录下读取特定文件类型,并没有生成java类。
1.插件工程
1.1 工程结构
1.2 Mojo类
注意点
1.3 插件工程的pom文件
可以看到 goalPrefix 对应的属性值和mojojava类中的值时一样的
2 使用插件的工程
2.1 工程结构
2.2 pom文件
注意点:
在使用插件的工程中创建/src/main/resources/yml文件,存入test.yml内容如下:
执行maven package命令,可以在控制台看到maven插件正确执行,解析的test.yml文件的内容
完整工程代码请参考附件
- Build plugins:在build阶段执行,在pom中必须配置在<build/>标签里面
- Reporting plugins:在生成site阶段执行,在pom中配置在<reporting/>标签里面。
maven官方已经给我们提供了各种各样的插件maven plugins,但有时我们还是需要自己定义我们特殊的插件,比如我们项目中根据特定的文件,自动生成对应的java类,这时就需要我们实现自己的特定插件了,本示例包含两个工程,
- 插件工程:maven-plugin-test
- 使用插件的工程:maven-plugin-client-test
为了使示例保持简单,插件工程只演示了从特定目录下读取特定文件类型,并没有生成java类。
1.插件工程
1.1 工程结构
1.2 Mojo类
/** * */ package falcon.chengf.maven.plugin.test; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; import java.util.Map; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.model.fileset.FileSet; import org.apache.maven.shared.model.fileset.util.FileSetManager; import org.yaml.snakeyaml.Yaml; /** * read content from yaml files (.yml) * * @goal readyml * @phase generate-sources * @threadSafe */ public class ReadYmlMojo extends AbstractMojo { /** * The source directory of yml files. This directory is added to the * classpath at schema compiling time. All files can therefore be referenced * as classpath resources following the directory structure under the source * directory. * * @parameter property="sourceDirectory" * default-value="${basedir}/src/main/resources" */ private File sourceDirectory; /** * @parameter property="outputDirectory" * default-value="${project.build.directory}/generated-sources/yml" */ private File outputDirectory; /** * @parameter property="sourceDirectory" * default-value="${basedir}/src/test/resources" */ private File testSourceDirectory; /** * @parameter property="outputDirectory" * default-value="${project.build.directory}/generated-test-sources/yml" */ private File testOutputDirectory; /** * A set of Ant-like inclusion patterns used to select files from the source * directory for processing. By default, the pattern * <code>**/*.yml</code> is used to select grammar files. * * @parameter property="includes" **/ private String[] includes = new String[] { "**/*.yml" }; /** * A set of Ant-like inclusion patterns used to select files from the source * directory for processing. By default, the pattern * <code>**/*.yml</code> is used to select grammar files. * * @parameter */ private String[] testIncludes = new String[] { "**/*.yml" }; /** * A set of Ant-like exclusion patterns used to prevent certain files from * being processed. By default, this set is empty such that no files are * excluded. * * @parameter */ protected String[] excludes = new String[0]; /** * A set of Ant-like exclusion patterns used to prevent certain files from * being processed. By default, this set is empty such that no files are * excluded. * * @parameter */ protected String[] testExcludes = new String[0]; /** * The current Maven project. * * @parameter default-value="${project}" * @readonly * @required */ protected MavenProject project; /* * (non-Javadoc) * * @see org.apache.maven.plugin.Mojo#execute() */ public void execute() throws MojoExecutionException, MojoFailureException { getLog().info("start to read content from yml file"); getLog().info("sourceDirectory:" + sourceDirectory.getAbsolutePath()); getLog().info("outputDirectory:" + outputDirectory.getAbsolutePath()); getLog().info("includes:" + Arrays.asList(includes)); boolean hasSourceDir = null != sourceDirectory && sourceDirectory.isDirectory(); boolean hasTestDir = null != testSourceDirectory && testSourceDirectory.isDirectory(); if (!hasSourceDir && !hasTestDir) { throw new MojoExecutionException("neither sourceDirectory: " + sourceDirectory + " or testSourceDirectory: " + testSourceDirectory + " are directories"); } if (hasSourceDir) { String[] includedFiles = getIncludedFiles(sourceDirectory.getAbsolutePath(), excludes, getIncludes()); readFiles(includedFiles, sourceDirectory, outputDirectory); } if (hasTestDir) { String[] includedFiles = getIncludedFiles(testSourceDirectory.getAbsolutePath(), testExcludes, getTestIncludes()); readFiles(includedFiles, testSourceDirectory, testOutputDirectory); project.addTestCompileSourceRoot(testOutputDirectory.getAbsolutePath()); } getLog().info("read from yml file end"); } /** * 根据条件过滤需要处理的文件 * @param absPath * @param excludes * @param includes * @return */ private String[] getIncludedFiles(String absPath, String[] excludes, String[] includes) { FileSetManager fileSetManager = new FileSetManager(); FileSet fs = new FileSet(); fs.setDirectory(absPath); fs.setFollowSymlinks(false); for (String include : includes) { fs.addInclude(include); } for (String exclude : excludes) { fs.addExclude(exclude); } return fileSetManager.getIncludedFiles(fs); } private void readFiles(String[] files, File sourceDir, File outDir) throws MojoExecutionException { for (String filename : files) { getLog().info("read content from file " + filename); try { doRead(filename, sourceDir, outDir); } catch (IOException e) { throw new MojoExecutionException("Error compiling protocol file " + filename + " to " + outDir, e); } } } private static final Yaml yaml = new Yaml(); protected void doRead(String filename, File sourceDirectory, File outputDirectory) throws IOException { File src = new File(sourceDirectory, filename); // 通过snakeyml读取yml文件内容 Map<String,Object> content= (Map)yaml.load(new FileInputStream(src)); getLog().info(filename+"'s content is"+content.toString()); } protected String[] getIncludes() { return includes; } protected String[] getTestIncludes() { return testIncludes; } }
注意点
- 1.ReadYmlMojo类上面的注释中有三个注解,这三个注解有特定含义,不能省略,其中@goal 对应的值(readyml)必须和pom.xml中的goal一致
- 2.属性上面注释中的@parameter注解也有特殊含义,不能省略,如sourceDirectory上的@parameter property="sourceDirectory"要和使用插件工程的pom中指定的参数一致
1.3 插件工程的pom文件
<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>falcon.chengf</groupId> <artifactId>maven-plugin-test</artifactId> <version>1.0</version> <packaging>maven-plugin</packaging> <name>maven-plugin-test</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.version>2.0.10</maven.version> <file-management.version>1.2.1</file-management.version> </properties> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-project</artifactId> <version>${maven.version}</version> </dependency> <dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>file-management</artifactId> <version>${file-management.version}</version> </dependency> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-utils</artifactId> <version>3.0.8</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.2</version> <configuration> <goalPrefix>readyml</goalPrefix> <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> </configuration> <executions> <execution> <id>mojo-descriptor</id> <goals> <goal>descriptor</goal> </goals> </execution> <execution> <id>help-goal</id> <goals> <goal>helpmojo</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <profiles> <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile> </profiles> </project>
可以看到 goalPrefix 对应的属性值和mojojava类中的值时一样的
2 使用插件的工程
2.1 工程结构
2.2 pom文件
<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>falcon.chengf</groupId> <artifactId>maven-plugin-client-test</artifactId> <version>0.0.1-SNAPSHOT</version> <name>maven-plugin-client-test</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <sourceDirectory>${project.basedir}/target/generated-sources</sourceDirectory> <plugins> <plugin> <groupId>falcon.chengf</groupId> <artifactId>maven-plugin-test</artifactId> <version>1.0</version> <configuration> <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> </configuration> <executions> <execution> <id>readyml</id> <phase>generate-sources</phase> <goals> <goal>readyml</goal> </goals> <configuration> <sourceDirectory>${project.basedir}/src/main/resources/yml</sourceDirectory> <outputDirectory>${project.basedir}/target/generated-sources</outputDirectory> <includes> <include>**/*.yml</include> </includes> </configuration> </execution> </executions> </plugin> </plugins> <pluginManagement> <plugins> <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. --> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <pluginExecution> <pluginExecutionFilter> <groupId>falcon.chengf</groupId> <artifactId> maven-plugin-test </artifactId> <versionRange> [0.0.1-SNAPSHOT,) </versionRange> <goals> <goal>readyml</goal> </goals> </pluginExecutionFilter> <action> <ignore></ignore> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
注意点:
- execution中的id属性要和插件工程对应的goal一致
- configuration中的属性如outputDirectory要和插件工程中@parameter的property值一致
- 在eclipse中引用插件工程后回报如下错误
直接选择第二项忽略即可
在使用插件的工程中创建/src/main/resources/yml文件,存入test.yml内容如下:
name: chengf level: 11
执行maven package命令,可以在控制台看到maven插件正确执行,解析的test.yml文件的内容
完整工程代码请参考附件