このガイドについて

Mavenユーザガイドは、開発者がMavenに精通できるように、 完全な説明や例を用いて書かれています。 もし、提案やコメントがあれば、自由に Maven users' listに投稿してください。

Mavenをご選択いただきありがとうございます!

導入

Mavenは、当初Jakarta Turbineプロジェクトのビルドプロセスを単純化する目的でスタートしました。 いくつかのプロジェクトでは独自のAntビルドファイルを持っていましたが、 違いはほとんどありませんでした。 また、JARはCVSにチェックインされていました。 プロジェクトをビルドする標準的な方法や、プロジェクトの構成物の明確な定義、 プロジェクトの情報を簡単に公開する方法、 複数のプロジェクト間でJARを共有する方法が欲しかったのです。

その結果、どんなJavaのプロジェクトのビルド、管理に使用できるツールとなりました。 私達が作成したものが、Java開発者の日常作業を簡単にし、 基本的にどんなJavaのプロジェクトでも理解の助けとなるものであることを願います。

プロジェクトオブジェクトモデル

Mavenはプロジェクトオブジェクトモデル(POM)の考えに基づいています。 この考えでは、Mavenが生成する全ての生成物は、 プロジェクトを良く定義したモデルを調査した結果となります。 ビルド、ドキュメンテーション、ソースメトリクス、ソースの相互参照など、 MavenのPlug-inが提供するものは、全てPOMで制御されます。

POMの処理

ここで、Mavenの実行時にPOMがどのように処理されるのか、概要を説明します。 POMを継承するいくつかの簡単な形式を示します。そして、改変のメカニズムをお見せします。

POMの改変

project.xml形式で知られているPOMは、Jellyスクリプトとして処理されます。 ほとんどの場合はproject.xmlがJellyスクリプトとして動作することをユーザが意識することはありません。 しかし、ユーザが望むなら、この事実を利用して値を改変することができます。 突発的にproject.xmlにロジックスタートを書き込むよりも、 project.xmlファイルが隠れたJellyスクリプトであるため柔軟になっていると理解することを勧めます :-) 可能なことの例を以下に示します:

        <?xml version="1.0" encoding="ISO-8859-1"?>
        <project>

          <pomVersion>3</pomVersion>
          <id>maven</id>
          <name>Maven</name>
          <currentVersion>1.0-b5-dev</currentVersion>
          <organization>
            <name>Apache Software Foundation</name>
            <url>http://jakarta.apache.org/</url>
            <logo>/images/jakarta-logo-blue.gif</logo>
          </organization>
          <inceptionYear>2001</inceptionYear>
          <package>org.apache.${pom.id}</package>
          <logo>/images/${pom.id}.jpg</logo>

          <description>Maven is a project that was created in ${pom.inceptionYear}.</description>
          <shortDescription>${pom.name} is a Java Project Management Tool</shortDescription>

        </project>

        

POMの継承

project.xml形式で馴染みがあるPOMを使用する場合、シンプルな形態の継承を利用可能です。 可能なことの例を以下に示します。

        <?xml version="1.0" encoding="ISO-8859-1"?>
        <project>
          <extend>project.xml</extend>
  
          <id>super-extendo</id>
          <name>Super Extendo</name>

          <build>
            <unitTest>
              <includes>
                <include>**/*Test*.java</include>
              </includes>
              <excludes>
                <exclude>**/TestAll.java</exclude>
                <exclude>**/*Abstract*.java</exclude>
              </excludes>
            </unitTest>
          </build>
        </project>
        

現在のところ、親の解決はかなりお馬鹿です。 そして、1階層以上拡張した場合のテストは行われていません。 しかし、このレベルの拡張でも、改変と組み合わせることで、 潜在的に多くのことをもたらします。 commonsのビルドを単純にしようとして、この機能があります。

次のようにマスターテンプレートを定義します:

        <project>
          <pomVersion>3</pomVersion>
          <id>commons-master</id>
          <name>Commons Master Maven POM</name>
          <groupId>org.apache.commons</groupId>

          <organization>
            <name>Apache Software Foundation</name>
            <url>http://www.apache.org</url>
          </organization>

          <gumpRepositoryId>jakarta</gumpRepositoryId>

          <url>http://jakarta.apache.org/commons/${pom.id}.html</url>
          <issueTrackingUrl>http://nagoya.apache.org/</issueTrackingUrl>
          <siteAddress>jakarta.apache.org</siteAddress>
          <siteDirectory>/www/jakarta.apache.org/commons/${pom.id}/</siteDirectory>
          <distributionDirectory>/www/jakarta.apache.org/builds/jakarta-commons/${pom.id}/</distributionDirectory>

          <repository>
            <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/${pom.id}</connection>
            <url>http://cvs.apache.org/viewcvs/jakarta-commons/${pom.id}/</url>
          </repository>
          ...
        </project>

        

そして、次のように派生出来ます:

        <project>
          <id>commons-betwixt</id>
          <name>Betwixt</name>
          ...
        </project>
        

その結果、親のテンプレートで子の${pom.id}の値が代用されます。 commonsプロジェクトのように、基本的なセットアップ方法が同一な複数のビルドがあるプロジェクトでは、 マスターテンプレートを使用し、ごく一部を子のproject.xmlファイルで設定することが出来ます。

また、これで複数のJARファイルを生成する1つのプロジェクトを扱うのが簡単になるはずです。 project.xmlが通常のAntビルドに干渉しないか、commonsで継承のテストを計画しています。

DVSLのレポートがこのメカニズムを使っているように見えたなら、いいところを突いています。 DVSLのレポートがPOMそのものに対して動作するように変更しました。 つまり、DVSL変換がJavaのオブジェクトに対して実行されます。 改変と継承が組み合わさったときに正確にレポートを出すために必要でした。 上記の子のテンプレートを使うことができず、また動作もしません。 完全に解決されたPOMを使用する必要があります。 出来る限りお伝えするなら、現在作業中と言うことです。 今行っている処理は、おそらくもっとも有効なものではないでしょうが、 改善できます。 現在のところPOMは1度しか処理されないので(とにかく、これが理論です。 少し失敗だったかも知れませんけども)、もしかすると壊してしまうでしょう。 そしてすべての場所で使えます。 少なくとも、それが、私がこの経路で行っていたことです。

継承や改変を使わなければ、すべては普段通り動作します。 Mavenのサイトは正常に動作しているようです。 また、最後に配置したいくつかのサイトでは、今夜このあとコミットする予定の機能を使っています。

プラグインを使用する

簡潔に言うと、Mavenとはプラグインと動作する小さなコアです。 Mavenで提供される機能はすべてプラグインとして実行されます。

maven.xmlファイル

プロジェクトのmaven.xmlファイルは、Mavenが処理を実行中に探す "特別な"ファイルです。

Mavenのビルド処理に更に処理を追加するために使われます。 あるいは、jartestといったMavenの"ゴール"を実行する前や後に独自のコードを付加するために使われます。

MavenはJelly をスクリプト言語として使用します。 有効なJellyのタグならどれでもmaven.xmlに書くことが出来ます。

Mavenが使うgoalの機能は、Jellyのwerkz タグライブラリを使って提供されています。 werkzに関する更に詳しい情報は Jellyタグドキュメンテーションを参照下さい。

プロパティの処理

Mavenのプロパティファイルは以下の順番で処理されます:

  • ${maven.home}/bin/driver.properties
  • ${project.home}/project.properties
  • ${project.home}/build.properties
  • ${user.home}/build.properties

最後に定義されたものが有効です。 プロパティファイルをこの順番で走査して、 以前に定義されたプロパティを新しいもので置き換えます。 この順番では、処理されるプロパティファイルのリストの中で ${user.home}/build.propertiesが決定権を持ちます。 Mavenが処理するプロパティファイルのリストは、 標準プロパティファイルセットと呼ばれる予定です。

更に、上記のプロパティのチェーンが終わった後でシステムのプロパティが処理されます。 -Dproperty=valueの形式でCLIから指定したプロパティが、 それまでの定義すべてに優先して上書きされます。

プラグインのプロパティがどのように動作するか

上記のプロパティファイルのシーケンスが処理された後でプラグインが読み込まれます。 PluginManagerはこれまでに設定された値を上書きしないように通知されます。 Mavenの通常のプロパティ処理とは逆の方法で動作します。 Maven内部の他の部分が初期化された後でプラグインは処理されるにも関わらず、 次のように出現することを期待しているからです:

  • プラグインのデフォルトプロパティを処理する
  • ${maven.home}/bin/driver.propertiesを処理する
  • ${project.home}/project.propertiesを処理する
  • ${project.home}/build.propertiesを処理する
  • ${user.home}/build.propertiesを処理する

プラグインは初期化サイクルのあとの方で処理されます。 それでも、プラグインのデフォルトプロパティを任意の値で上書き出来ます。 例えばCheckstyleプラグインは以下のデフォルトプロパティを定義しています:

       maven.checkstyle.format = sun
       

ご想像通り、このプロパティはCheckstyleプラグインのデフォルトフォーマットとして、 Sunのコーディング規約を使用することを通知しています。 標準のプロパティファイルのセットに含まれる任意のファイルでこの値を上書きできます。 ${project.home}/project.propertiesに以下の値を記述したとします:

       maven.checkstyle.format = turbine
       

このとき、CheckstyleプラグインはTurbineのコーディング規約を使用します。

動作に関わるプロパティ

Mavenの動作方法を変更するプロパティの一覧を以下に示します。

プロパティ 説明 デフォルト値
maven.mode.online true
maven.remote.repo.enabled true

ビルド

Mavenは集中リポジトリの概念を使用して動作します。 集中リポジトリからビルドに必要な生成物を取得します。 現在、私たちの集中リポジトリはIbiblio内の ここで運営されています。 典型的なMavenのプロジェクトでは、必要なJARファイルは集中リポジトリから取り出されます。 Mavenは解決できない依存関係のファイルだけを取り出します。 Mavenを使っていくつかのプロジェクトをビルドしているなら、 いくつか共通する依存関係を持つことがよく起こります: Mavenは、1つのJARファイルを、それを必要とするすべてのプロジェクトで共有します。 システム上に複数のコピーが作られることはありません!

CVSでのJAR保存

CVSにJARファイルを保存することは推奨されません。 JARやその他プロジェクトの生成物を保存し、任意の数のビルドで使用される、 ユーザローカルリポジトリの概念を提案します。 多くのプロジェクトは、XMLパーサや標準ユーティリティのように、 典型的なAntのビルドで頻繁に複製される依存ファイルを持ちます。 Mavenを使用すると、ユーザローカルリポジトリにそれらの標準ユーティリティを保存し、 任意の数のビルドで共有されます。

プロキシの使用

プロキシを介さないとアクセスできない場合は、以下のプロパティを設定します。

プロキシプロパティ 説明
maven.proxy.host プロキシのIPアドレスもしくはアドレス
maven.proxy.port プロキシのポート番号
maven.proxy.username プロキシで認証が必要な場合に使用するユーザ名
maven.proxy.password プロキシで認証が必要な場合に使用するパスワード

プロキシが必要な場合、それらの値を設定するのにもっとも適切な場所は ${user.home}/build.propertiesファイルです。

## ----------------------------------------------------------
## ${user.home}/build.properties
## ----------------------------------------------------------
.
.
maven.proxy.host = my.proxyserver.com
maven.proxy.port = 8080
maven.proxy.username = username
maven.proxy.password = password
.
.

デプロイ

依存するJARファイルのコピー

プロジェクトが依存するJARファイルをコピーする最も簡単な方法は、 以下のサンプルmaven.xmlファイルをガイドとして使用することです:

      
        <project xmlns:deploy="deploy">
      
          <goal name="deploy-my-project">
        
            ...
          
            <deploy:copy-deps todir="/path"/>
        
            ...
        
          </goal>
      
        </project>
      
        

deploy:copy-depsタグを使うと、プロジェクトが依存する JARファイルを任意の場所にコピー出来ます。 特定のJARファイルを除外するには、依存関係IDのリストを与えます。 リストにある依存ファイルはコピーの対象から除外されます:

      
        <project xmlns:deploy="deploy">
      
          <goal name="deploy-my-project">
        
            ...
          
            <deploy:copy-deps todir="/path" excludes="servletapi,commons-util"/>
        
            ...
        
          </goal>
      
        </project>
      
        

命名規則

このセクションでは、Mavenのプロジェクトオブジェクト(POM) で使用する命名規則の概要を示します。 Java開発者コミュニティで広く使ってもらおうとして公開するプロジェクトの生成物の命名規則は、 多種多様になっています。 この文書は、これらの方法を試し、統一する試みです。

規則とガイドライン

プロジェクト

プロジェクトはアルファベット小文字[a-z]とハイフンで構成される固有の識別子を持たなければなりません。 識別子はアルファベット小文字[a-z]で始まる必要があります:

        
        <project>
          <id>foo</id>
          ...
        </project>
        
        

あるプロジェクトから別のプロジェクトへの参照は、 すべて固有のプロジェクトIDによって行われます。 今のところ、これが関連するPOMの項目は、後述するプロジェクトの依存関係の宣言だけです。

プロジェクトは人間が理解できる名前を持つべきです。 これは文書で使われます。

        
        <project>
          <id>foo</id>
          <name>The Grand Master Foo</name>
          ...
        </project>
        
        

プロジェクトはグループ識別子を持つべきです。 グループ識別子は名前の基礎となります。

        
        <project>
          <id>foo</id>
          <name>The Grand Master Foo</name>
          <groupId>org.foo.bar</groupId>
          ...
        </project>
        
        

プロジェクトが公開するすべての生成物は、 プロジェクトの固有な識別子に基づくべきです。 また、プロジェクトのグループ識別子に基づいたディレクトリに置くべきです。 つまり、前出の入力に対して、jarの生成物があるとすると、 以下のような形になります:

      
      repository
      |
      +-- org.foo.bar
          |-- distribution
          `-- jar
              |-- foo-1.0.jar
              `-- foo-2.0.jar
      
      

依存関係

依存関係を宣言する、理想的で典型的とあって欲しい例は、以下のとおりです:

        
        <project>
          <id>bar</id>
          <name>Baradelic Groove Machine</name>
          <groupId>org.bar.foo</groupId>
          ...
          
          <dependencies>
          
            <dependency>
              <groupId>org.foo.bar</groupId>
              <artifactId>foo</artifactId>
              <artifactType>jar</artifactType>
              <category>runtime</category>
              <version>1.0</version>
            </dependency>
          
          </dependencies>
          
        </project>
        
        

これは、グループ識別子org.foo.barのグループに属する、 識別子fooを持つ生成物の、 バージョン1.0に依存するプロジェクトbarとなります。 この依存関係はローカルリポジトリに保管されているJARファイルに解決されます。 上記の入力は、生成物の名前は識別子に基づいて公開されることを仮定しています。 つまり、上記の依存関係に対してfoo-1.0.jarというJARファイルを仮定します。

お気付きのように、この理想的な状態はすべてのプロジェクトで常に成り立つわけではありません。 理想的な依存関係の宣言を修正するために説明が必要ないくつかの状況があります。

  • プロジェクトIDを公開されるJARファイルの基底名として使っていないもの、 例えばXercesです。 XercesはxercesImplを公開するJARファイルの基底名にしています。 これはGump IDやMaven IDには該当しません。
  • 公開されたJARファイルの名前にバージョン宣言を持たないもの、 例えば、多くのcommonsコンポーネントです。 これらは公開するJARファイル名の一部として、 バージョンを宣言していません。
  • プロジェクトIDが公開されるJARファイルの基底名ではなく、 バージョン宣言も持たないもの、 Java Activation Frameworkの最悪のシナリオです。 僅かも他のSunの命名規約に則るわけでもなく、 ファイル名にバージョン宣言もありません。 マニフェストにすらバージョン情報はないのです。

多くの場合、これらの制限はオプションの<jar>の要素を使用したり JARファイルの名前を変えることで対処できます。 近い将来ほとんどのJakartaプロダクトでビルドにMavenを使用することが予想されるため、 日付を付けるためにリポジトリの多くのJakarta製品の名前が変えられました。 しかし解決しなければならないすべての場合に行うことに、 しっかりしたポリシーがあるわけではありません。

複数の生成物を持つプロジェクト

Mavenの依存関係のメカニズムは、どの種類の生成物でも、 プロジェクトの複数の生成物を完全にサポートします。

ant 1.4.1の基本JARファイルと、オプションJARファイルに、 いくつか仮定すると、このようエントリになります:

        

        <dependencies>
  
          <!-- A -->
          <dependency>
            <groupId>org.apache.tools.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.4.1</version>
          </dependency>
  
          <!-- B -->
          <dependency>    
            <groupId>org.apache.tools.ant</groupId>
            <artifactId>ant-optional</artifactId>
            <version>1.4.1</version>
          </dependency>

          <!-- C -->
          <dependency>
            <groupId>org.apache.tools.ant</groupId>
            <artifactId>poorly-named</artifactId>
            <version>1.4.1</version>
          </dependency>

        </dependencies>

        
        

A)、B)、C)は1つのグループの、単一の生成物を実際に示しています。 つまり、単一の依存関係はグループの単一の生成物に対する参照になります。 現在は、すべて、JARがデフォルトとなっています。 依存関係をJavaDocのインデックスとし、他のJavaDocのインデックスと結合した、 全体的なインデックスを形成することも考えられています。 また配布ファイルに含めたい任意のリソースを指定することも考えられています。 私たちはこれらをオープンにしたままにするつもりです。 一方で、最も使われるケースは、生成物が他のビルドに必要なJARである、 という状態を維持したいと考えています。

リモートリポジトリのレイアウト

この文書では、Mavenのリモートリポジトリのレイアウトの概要を示します。 現在のところ、Ibiblioのここで、 第一のリポジトリが運営されています。 また、この文書で概要を示した構造を忠実に提供すれば、 独自のリモートリポジトリを作成することも出来ます。

すべてのプロジェクトは個別のディレクトリを持ちます。 その中にプロジェクトの生成物を保管します。 各プロジェクトは固有のプロジェクト識別子とディレクトリを持ち、 プロジェクトの識別子から命名される生成物を保管します。

プロジェクトのディレクトリには様々な種類の生成物が保管されます。 現在のところは最も一般的なのは、JARファイルと配布ファイルの2種類です。 以下は、リモートリポジトリの小さなスナップショットの一例です:

      
      repository
      |
      |-- org.apache.tools.ant
      |   |-- distribution
      |   `-- jar
      |       |-- ant-1.4.1.jar
      |       `-- ant-optional-1.4.1.jar
      +-- jsse
      |-- distribution
      `-- jar
          |-- jsse.jar
          |-- jcert.jar
          `-- jnet.jar
      
      

ローカルリポジトリのレイアウト

任意の方式のローカルリポジトリ構造を扱うインターフェイスの、 本当に最低限の実装があります。 辛うじて肉付けされた状態で、現在、私はパッケージの1つのクラスだけを直接使っています。 ローカルとリモートのリポジトリは同一の構造を持つべきと今でも考えています。 しかし、ローカルリポジトリのレイアウトはユーザの任意とし、 かつ、リモートリポジトリは一貫したインターフェイスとする、 ユーザが喜びそうな試みを始めました。 ただし、今はまだローカルリポジトリの構造はリモートリポジトリと同一にする必要があります。 インターフェイスを完成に近づけるために、あるいは全部ひっくるめて取りやめるために、 もっと多くのフィードバックを下さい。

複数のプロジェクトのビルド

Mavenは、リアクタツールを使って、複数のプロジェクトのビルドをコントロールします。 リアクタは、それぞれのプロジェクトのPOMに書かれた依存関係に基づいた正しいビルド順を commons-graphパッケージを使って決定します。 現在リアクタを鋭意改良中です。また、リアクタへの入口となる2、3の実行例があります: