編寫maven代碼行統計插件

編寫maven插件的步驟java

  1. 建立一個maven-plugin項目:插件自己也是maven項目,只是它的packaging是maven-plugin。
  2. 爲插件編寫目標:每一個插件必須包含一個或多個目標,maven稱之爲Mojo。編寫插件時必須提供一個或多個繼承自AbstractMojo的類。
  3. 爲目標提供配置點:大部分maven插件以及其目標都是可配置的,所以在編寫Mojo的時候須要注意提供可配置的參數。
  4. 編寫代碼,實現目標。
  5. 錯誤處理以及日誌,爲客戶提供足夠的信息。
  6. 測試插件

一:建立maven-plugin項目web

建立一個普通的maven項目,只是packaging改成maven-plugin,同時引入依賴maven-plugin-api。pom文件以下:sql

<?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>com.sawyer.edu</groupId>
    <artifactId>maven-loc-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>maven-plugin</packaging>

    <properties>
        <maven.version>3.0</maven.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>${maven.version}</version>
        </dependency>
    </dependencies>

</project>

二:建立一個CountMojo類。該類所必要的三項工做:繼承AbstractMojo、實現execute()方法、提供@goal標註。代碼以下:express

package com.sawyer.edu.tlsys.plugin;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * maven 代碼統計插件
 * @author sawyer
 * @goal count
 */
public class CountMojo extends AbstractMojo {

    /**
     * default includes
     */
    private static final String[] INCLUDES_DEFAULT = {"java", "xml", "properties"};

    /**
     * @parameter expression = "${project.basedir}"
     * @required
     * @readonly
     */
    private File basedir;

    /**
     * @parameter expression = "${project.build.sourceDirectory}"
     * @required
     * @readonly
     */
    private File sourceDirectory;

    /**
     * @parameter expression = "${project.build.testSourceDirectory}"
     * @required
     * @readonly
     */
    private File testSourceDirectory;

    /**
     * @parameter expression = "${project.build.resources}"
     * @required
     * @readonly
     */
    private List<Resource> resources;

    /**
     * @parameter expression = "${project.build.testResources}"
     * @required
     * @readonly
     */
    private List<Resource> testResources;

    /**
     * file types which will be included for counting
     * @parameter
     */
    private String[] includes;

    /**
     * execute
     * @throws MojoExecutionException MojoExecutionException
     * @throws MojoFailureException MojoFailureException
     */
    public void execute() throws MojoExecutionException, MojoFailureException {
        if(includes == null || includes.length == 0){
            includes = INCLUDES_DEFAULT;
        }
        try{
            countDir(sourceDirectory);
            countDir(testSourceDirectory);
            for(Resource resource : resources){
                countDir(new File(resource.getDirectory()));
            }
            for(Resource testResource : testResources){
                countDir(new File(testResource.getDirectory()));
            }
        }catch (Exception e){
            throw new MojoExecutionException("count failed:", e);
        }
    }

    /**
     * 統計某個目錄下文件的代碼行
     * @param dir 目錄
     * @throws IOException 文件異常
     */
    private void countDir (File dir) throws IOException{
        if(!dir.exists()){
            return;
        }
        List<File> collected = new ArrayList<File>();
        collectFiles(collected, dir);
        int lines = 0;
        for(File sourceFile : collected){
            lines += countLine(sourceFile);
        }
        String path = dir.getAbsolutePath().substring(basedir.getAbsolutePath().length());
        getLog().info(path + ": " + lines + " lines of code in " + collected.size() + "files");
    }

    /**
     * 遞歸獲取文件列表
     * @param collected 文件列表list
     * @param file 文件
     */
    private void collectFiles(List<File> collected, File file){
        if(file.isFile()){
            for(String include : includes){
                if(file.getName().endsWith("." + include)){
                    collected.add(file);
                    break;
                }
            }
        }else{
            for(File sub : file.listFiles()){
                collectFiles(collected, sub);
            }
        }
    }

    /**
     * 讀取文件的行數
     * @param file 文件對象
     * @return line
     * @throws IOException 文件操做異常
     */
    private int countLine(File file) throws IOException{
        BufferedReader reader = new BufferedReader(new FileReader(file));
        int line = 0;
        try{
            while(reader.ready()){
                reader.readLine();
                line++;
            }
        }finally {
            reader.close();
        }
        return  line;
    }
}
CountMojo代碼

這裏要關注的是@goal標註,這個標註就是這個類的目標,定義了目標以後,咱們才能夠在項目中配置該插件目標。apache

代碼中還包含了basedir、sourceDirectory、testSourceDirectory等字段,它們都使用了@parameter標註,同時關鍵字expression表示從系統屬性中讀取這幾個字段值。api

其次,代碼中的includes字段就是用來爲用戶提供該配置點的,它的類型爲String數組,而且使用了@parameter參數表示用戶能夠本身在pom中配置該字段,使用該插件時的pom配置以下:數組

<plugin>
    <groupId>com.iflytek.edu</groupId>
    <artifactId>maven-loc-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <configuration>
        <includes>
            <include>java</include>
            <include>sql</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>count</goal>
            </goals>
        </execution>
    </executions>
</plugin>

根據上面的pom配置,能夠看到incuudes字段標識須要統計的文件後綴,phase表示該插件在compile階段工做,使用該插件的時候能夠看到以下輸出信息:app

[INFO] --- maven-loc-plugin:1.0-SNAPSHOT:count (default) @ ZX-jobmonitor-webapp ---
[INFO] \src\main\java: 778 lines of code in 6files
[INFO] \src\test\java: 0 lines of code in 0files
[INFO] \src\main\resources: 0 lines of code in 0files

 使用mvn clean install命令將該插件項目構建並安裝到本地倉庫後,並按照上面的pom配置,就能夠使用它統計項目的代碼了。webapp

三:錯誤處理和日誌maven

上面的CountMojo類繼承自AbstratctMojo,跟蹤會發現該抽象類實現了類Mojo接口,execute()方法就是在這個接口中定義的。

void execute()
        throws MojoExecutionException, MojoFailureException;

這個方法能夠拋出兩種異常,

若是是MojoFailureException異常,則表示爲發現了預期的錯誤,例如單元測試插件在發現測試失敗時就會拋出該異常。

若是是MojoExcutionException異常,則表示發現了未預期的異常,例如上述代碼中的IOException等。

四:測試

可在項目中直接集成該插件,也能夠在項目目錄下用命令行來測試該插件,命令以下:

mvn com.sawyer.edu:maven-loc-plugin:1.0-SNAPSHOT:count
相關文章
相關標籤/搜索