1. 程式人生 > >Maven的Java外掛開發指南

Maven的Java外掛開發指南

原文地址 譯者:劉小劉

介紹

本指南的目標是幫助使用者使用Java開發Maven外掛。

重要宣告:外掛命名規範和Apache Maven商標

通常將你的外掛命名為<yourplugin>-maven-plugin。
強烈反對命名為maven-<yourplugin>-plugin(maven在外掛名開頭),因為這是Apache Maven組織為官方Maven外掛保留的命名格式,用org.apache.maven.plugins作為組id。使用此命名是對Apache Maven商標的侵權。

你的第一個外掛

這一部分我們將構建一個不帶引數、執行時輸出一行資訊的簡單外掛,會覆蓋建立外掛專案的基本操作、Java Mojo的核心內容,以及執行Mojo的兩種方式。

你的第一個Mojo

最簡單地,一個Java Mojo只包含一個類。不需要像EJB有多個類,儘管包含一組相似Mojo的外掛很可能提取一個抽象基類以合併公共程式碼。
在程式碼樹中搜索Mojo時,plugin-tools尋找帶有@Mojo形式的Java5註解的類或帶有goal的javadoc型註解。所有帶有這樣註解的類包含在外掛配置檔案中。

一個簡單的Mojo

下面是一個簡單的無引數Mojo類,它可能是最簡單的Mojo了。程式碼示例後面是各部分的說明。

package sample.plugin;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;

/**
 * Says "Hi" to the user.
 *
 */
@Mojo( name = "sayhi")
public class GreetingMojo extends AbstractMojo
{
    public void execute() throws MojoExecutionException
    {
        getLog().info( "Hello, world." );
    }
}
  • 類org.apache.maven.plugin.AbstractMojo提供了實現一個Mojo需要的大部分基礎功能,除了execute方法。
  • “@Mojo”註解是必須的,它控制了Mojo何時和怎樣被執行
  • execute方法可以丟擲兩種異常:
  • org.apache.Maven.plugin.MojoExecutionException 如果發生了非預期的錯誤丟擲此異常,顯示”BUILD ERROR”資訊。
  • org.apache.Maven.plugin.MojoFailureException 如果發生了預期內的錯誤(例如編譯錯誤)丟擲此異常,顯示“BUILD FAILURE”資訊。
  • getLog方法(在AbstractMojo中定義)返回一個類似log4j的日誌物件,外掛可以用它輸出debug, info, warn, error級別的日誌。這個日誌是使用者可接受的顯示資訊的方式。檢視
    Retrieving the Mojo Logger
     瞭解如何恰當使用。

專案定義

外掛的Mojo寫完後,就可以構建外掛了。外掛描述中需要設定以下幾項:

groupId 外掛的組id,應當與Mojo包名的共同字首一致
artifactId 外掛名
version 外掛版本
packaging 應設為”maven-plugin”
dependencies 必須宣告對Maven Plugin Tools API的依賴以解析”AbstractMojo”和相關類

下面是示例Mojo的pom示例,引數按上表要求設定:

<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>sample.plugin</groupId>
  <artifactId>hello-maven-plugin</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>maven-plugin</packaging>

  <name>Sample Parameter-less Maven Plugin</name>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.0</version>
    </dependency>

    <!-- dependencies to annotations -->
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.4</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
</project>

構建目標

在maven-plugin中定義了很少幾個目標作為標準構建生命週期的一部分:

compile 編譯外掛的Java程式碼,構建外掛描述
test 執行外掛的單元測試
package 構建外掛jar包
install 將外掛jar安裝到本地倉庫
deploy 將外掛jar部署到遠端倉庫

執行你的第一個Mojo

執行新外掛的最直接方式是在命令列直接指定外掛目標。要這樣做,你需要在專案中這樣配置hello-Maven-plugin:

...
  <build>
    <plugins>
      <plugin>
        <groupId>sample.plugin</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
      </plugin>
    </plugins>
  </build>
...

然後,指定目標的全名:

mvn groupId:artifactId:version:goal

例如,要執行示例外掛的Mojo,在命令列輸入“mvn sample.plugin:hello-Maven-plugin:1.0-SNAPSHOT:sayhi”。
注:執行單一目標不需要指定版本。

縮短命令列

有幾種方式縮短輸入:

  • 如果執行本地倉庫安裝的最新版外掛,可以省略版本號。使用”mvn sample.plugin:hello-Maven-plugin:sayhi”執行。
  • 賦予外掛一個短字首,如mvn hello:sayhi。如果按照${prefix}-maven-plugin的命名方式(如果外掛是Apache Maven的官方外掛用maven-${prefix}-plugin)這是自動完成的。也可以通過額外的配置設定字首,更多資訊參見Introduction to Plugin Prefix Mapping
  • 最後,可以把外掛的組id加入預設搜尋的組id列表。這種方式需要在${user.home}/.m2/settings.xml中增加如下配置:
    <pluginGroups>
      <pluginGroup>sample.plugin</pluginGroup>
    </pluginGroups>
    

此時,可以用”mvn hello:sayhi”執行Mojo了。

將Mojo關聯到構建生命週期

你也可以配置外掛關聯到構建生命週期某個特定階段的指定目標,示例如下:

 <build>
    <plugins>
      <plugin>
        <groupId>sample.plugin</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>sayhi</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

這樣Java程式碼編譯時這個簡單Mojo就會執行。更多繫結Mojo到生命週期階段的資訊,參考 Build Lifecycle

Mojo原型

利用Mojo原型建立新外掛專案:

mvn archetype:generate \
  -DgroupId=sample.plugin \
  -DartifactId=hello-maven-plugin \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DarchetypeArtifactId=maven-archetype-plugin

引數

不帶引數的Mojo一般沒太大用處,引數提供了以下重要功能:

  • 提供了讓使用者調整外掛操作以適應應用的鉤子
  • 提供一種不需要導航到物件就能提取POM元素值的簡單方式

定義Mojo引數

定義一個引數很簡單,只需要在Mojo中建立一個例項變數並增加恰當的註解。以下是帶引數的簡單Mojo示例:

 /**
     * The greeting to display.
     */
    @Parameter( property = "sayhi.greeting", defaultValue = "Hello World!" )
    private String greeting;

註解之前的部分是引數說明。引數註解將變數宣告為Mojo引數。註解的defaultValue引數定義了變數的預設值。這個值可以包含引用專案變數的表示式,如”{project.version}”(在  “Parameter Expressions” document能看到更多)。property引數支援引用使用者在命令列中通過-D指定的系統屬性。

在專案中配置引數

作為外掛定義的一部分,外掛的引數值配置在Maven專案的pom.xml中完成,示例:

<plugin>
  <groupId>sample.plugin</groupId>
  <artifactId>hello-maven-plugin</artifactId>
  <version>1.0-SNAPSHOT</version>
  <configuration>
    <greeting>Welcome</greeting>
  </configuration>
</plugin>

在configuration部分,名為”greeting”的元素名是引數的名稱,元素的值”Welcome”是賦予引數的值。
注意:更多細節參見 Guide to Configuring Plugins

單值引數型別

下面是可作為Mojo引數的簡單變數型別及其值在pom中的解釋規則。

Boolean

包括boolean和Boolean。讀配置時,讀到true字串時將引數設為true,讀到其它字串將引數設為false。例如:

 /**
     * My boolean.
     */
    @Parameter
    private boolean myBoolean;
<myBoolean>true</myBoolean>
定點數

包括byte, Byte, int, Integer, long, Long, short和Short。讀配置時,xml中的文字通過Integer.parseInt()或對應型別的valueOf()方法轉為整型數。字串必須是有效的十進位制整數,只包含數字0到9和可選的前置“-”表示負數。例如:

 /**
     * My Integer.
     */
    @Parameter
    private Integer myInteger;
<myInteger>10</myInteger>
浮點數

包含double, Double, float和Float。讀配置時,使用對應型別的valueOf()將xml中的文字轉為二進位制。文字可以是Java語言規範3.10.2節規定的任意格式。有效值示例如1.0和6.02E+23。

 /**
     * My Double.
     */
    @Parameter
    private Double myDouble;
<myDouble>1.0</myDouble>
日期

包括Date型別。讀配置時,xml中的文字按”yyyy-MM-dd HH:mm:ss.S a”(如”2005-10-06 2:22:55.1 PM”)或”yyyy-MM-dd HH:mm:ssa”(如”2005-10-06 2:22:55PM”)格式轉換。注意解析通過DateFormat.parse()完成,允許格式的少許偏差。這個方法盡力解析出日期和時間,即使格式不嚴格地匹配上述格式,例如:

 /**
     * My Date.
     */
    @Parameter
    private Date myDate;
<myDate>2005-10-06 2:22:55.1 PM</myDate>
檔案和目錄

包括File類。讀配置時,xml檔案中的文字被當做需要的檔案或目錄路徑。如果是相對路徑(不以/或驅動器字母如C:開頭),路徑是相對於POM所在目錄。例如:

 /**
     * My File.
     */
    @Parameter
    private File myFile;
<myFile>c:\temp</myFile>
URL

包含URL類。讀配置時,xml中的文字被當做URL。格式必須遵循RFC2396,看起來像web瀏覽器的URL(scheme://host:port/path/to/file)。轉換URL時對它的任何部分沒有限制。

  /**
     * My URL.
     */
    @Parameter
    private URL myURL;
<myURL>http://maven.apache.org</myURL>
普通文字

包含char, Character, StringBuffer和String。讀配置時,xml檔案中的文字被當做賦予引數的值。對char和Character引數,只使用文字的第一個字元。

列舉

也可以使用列舉型別變數。首先需要定義列舉型別,然後就可以在引數定義中使用了。

 public enum Color {
      GREEN,
      RED,
      BLUE
    }

    /**
     * My Enum
     */
    @Parameter
    private Color myColor;

在pom配置中可以使用這樣的列舉:

<myColor>GREEN</myColor>

也可以使用列舉型別的元素作為預設值,像下面這樣:

 public enum Color {
      GREEN,
      RED,
      BLUE
    }

    /**
     * My Enum
     */
    @Parameter(defaultValue = "GREEN")
    private Color myColor;

多值引數型別

下面介紹可以在Mojo中作為引數使用的各種複合物件,及它們在POM中的解釋規則。一般來說,儲存引數值(和引數值中的元素)的物件的型別是按以下步驟決定的(確定有效型別的第一步):
1. 如果XML元素包含implementation屬性,就使用它
2. 如果XML標籤包含”.”,嘗試解析為類的全名
3. 嘗試將XML標籤(首字母大寫)解析為Mojo所在包中的類
4. 對陣列,使用陣列的元素型別(例如,對String[]引數使用String型別);對集合和對映,使用Mojo配置中指定的類;使用String作為集合型別的entry和map的值的型別。

一旦元素的型別確定了,xml中的文字將被轉換為恰當的物件。

陣列

陣列引數通過多次指定來配置,例如:

 /**
     * My Array.
     */
    @Parameter
    private String[] myArray;
<myArray>
  <param>value1</param>
  <param>value2</param>
</myArray>
集合

這一類包含所有實現java.util.Collection的類,如ArrayList或HashSet。這些引數也像陣列一樣通過多次指定來配置,例如:

 /**
     * My List.
     */
    @Parameter
    private List myList;
<myList>
  <param>value1</param>
  <param>value2</param>
</myList>

關於獨立集合元素的對映細節,檢視 Mapping Lists.。

對映

這一類包含所有實現java.util.Map而未實現java.util.Properties的類,如HashMap。這些引數通過包含XML標籤來配置,形如<key>value</key>,例如:

   /**
     * My Map.
     */
    @Parameter
    private Map myMap;
<myMap>
  <key1>value1</key1>
  <key2>value2</key2>
</myMap>

Properties
這一類包含所有實現java.util.Properties的對映。這些引數通過包含XML標籤配置,形如<property><name>myName</name> <value>myValue</value> </property>,例如:

   /**
     * My Properties.
     */
    @Parameter
    private Properties myProperties;
<myProperties>
  <property>
    <name>propertyName1</name>
    <value>propertyValue1</value>
  <property>
  <property>
    <name>propertyName2</name>
    <value>propertyValue2</value>
  <property>
</myProperties>

其它物件型別
這一類包含所有未實現java.util.Map、java.util.Collection和java.util.Dictionary的類。例如:

 /**
     * My Object.
     */
    @Parameter
    private MyObject myObject;
<myObject>
  <myField>test</myField>
</myObject>

使用setters

如果你想在Maven上下文之外重用Mojo,私有屬性對映是好選擇,對它的使用沒有限制。按上面的示例我們可以使用下劃線風格命名私有屬性,並提供setter供配置對映機制使用,Mojo看起來是這樣的:

public class MyQueryMojo
    extends AbstractMojo
{
    @Parameter(property="url")
    private String _url;

    @Parameter(property="timeout")
    private int _timeout;

    @Parameter(property="options")
    private String[] _options;

    public void setUrl( String url )
    {
        _url = url;
    }

    public void setTimeout( int timeout )
    {
        _timeout = timeout;
    }

    public void setOptions( String[] options )
    {
        _options = options;
    }

    public void execute()
        throws MojoExecutionException
    {
        ...
    }
}

注意當屬性名和外掛配置中實際的引數名不一致時,對引數對應的屬性名的標記,這是用來告知Maven要使用的getter和setter。

資源