tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

Maven2のpom.xmlの構成

仕事でHudsonを導入したいと思っているのですが、Meven2と組み合わせた方がいろいろできるらしいので、Maven2について調べてみました。

半日くらいさわった後でのMaven2の印象


Mavenは1の頃にさわってみて、Antに逃げ帰った思い出があるので、そもそも悪い印象が多いのですが、そこは我慢してHudsonを使った運用を確立させるために頑張ってみます。

pom.xml

まずこのxmlが問題なわけです。
Mavenサイトに全体の構成が載っていますが、まずこれで使うのを止めたくなるわけです。
もう、どんな嫌がらせだよ、と。


と、思っていたのですが、単純な構成だと実はそんなに使う項目が多くなかったりします。

pom.xmlの構成(よく使うものだけ)
<?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/maven-v4_0_0.xsd">
  
  <!-- プロジェクト設定 -->
  
  <build>
    <!-- 入出力の設定 -->
    
    <plugins>
      <plugin>
         <!-- ビルド設定 -->
      </plugin>
    </plugins>
  </build>
  
  <reporting>
    <plugin>
      <!-- レポート設定 -->
    </plugin>
  </reporting>
  
  <dependencies>
    <dependency>
      <!-- ライブラリ依存関係の設定 -->
    </dependency>
  </dependencies>
  
</project>

コメントで書かれたところには、それぞれの子要素が入るので、そのまま実行できるわけではないのですが、こう見るとそんなに項目が多くないことがわかると思います。


以下、1つずつ追っていきます。

プロジェクト設定

  <groupId>jp.tanamon</groupId>
  <artifactId>mvntest</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <name>${project.artifactId}</name>
  <url>http://tanamon.jp/${project.artifactId}/</url>
groupId

組織としてユニークであればいいので、Javaのパッケージ名と同じにしておくとわかりやすいです。

artifactId

プロダクトごとにユニークであればいいので、Eclipseのプロジェクト名あたりと同じにしておくとわかりやすいです。

packaging

成果物をpom, jar, maven-plugin, ejb, war, ear, rar, parの中から指定します。

version

プログラムの変更ごとにユニークになるものだと思います。ナンバリングルールは社内でルール決めをすればよいです。しかし、実際の開発ではここに書かれていると管理が不便な気がするのですが、どう解決すべきかはそのうち調べます。

name

レポート等に出る表示名称です。artifactIdがapp0001みたいな名前にしなきゃいけないような不思議な組織がたまにあるので、そういった場合に表示名を別途指定できます。例では変数を使ってartifactIdと同じにしていますが、普通はこれでよいように思えます。

url

サイトのURLです。入口が複数ある場合はどうするんでしょうかね?

入出力設定

    <finalName>${project.artifactId}-${project.version}</finalName>
    <sourceDirectory>src/main/java</sourceDirectory>
    <outputDirectory>target/classes</outputDirectory>
    <testSourceDirectory>src/test/java</testSourceDirectory>
    <testOutputDirectory>target/test-classes</testOutputDirectory>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>

これらの設定値はデフォルト値です。Maven2推奨の構成らしいですが、特にディレクトリ構成など、この構成だとどう嬉しいのかそのうち調べます。
まぁ、最初は従っていたほうが余計な現象に悩まされなくていいと思います。

ビルド設定

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

Maven2は大抵の機能がプラグインによって実装されているため、ほとんどの場合、Maven2の機能を使うということはプラグインを追加する、ということになります。
また、ビルド設定とレポート設定(後述)は対になっているものが多いです。
ここではビルド時に使用するプラグインを指定します。


よく使われるプラグインAvailable Pluginsに一覧があります。
プラグインページのUsageのhereリンクの先に、使い方が載っています。
英語ですが、同じテンプレートで書かれているので、何とか読めると思います。


ちなみに、上記例はCompiler Pluginの設定になります。JDKのバージョンを指定できるものなので、大抵の開発で使うプラグインだと思います。

レポート設定

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <configuration>
          <docencoding>UTF-8</docencoding>
          <charset>UTF-8</charset>
          <encoding>MS932</encoding>
          <bottom></bottom>
        </configuration>
      </plugin>

こちらの設定もプラグインによって異なりますが、記述は大体一緒です。ここでは、レポート作成時に使用するプラグインを指定します。


上記例は、Javadoc Pluginの設定になります。
また、ウチの会社では残念なことにJavaソースがUTF-8化されていないので、文字コードをMS932にしています。

ライブラリ依存関係の設定

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

ライブラリの依存関係を明示的に指定できます。
ここに記述することで、たとえばUnitTest時にしか使用しないようなライブラリを除いたりすることができます。


とはいえ、ライブラリごとにgroupIdとartifactIdが違うため、Maven Repositoryから定義を探してきます。
上記例ではjunit 3.8.1のPOM Dependencyの記述からテンプレートが探せます。

version

versionは記述しないと、自動的に最新版を取得してきます。また、範囲指定をすることでマイナーバージョンアップの範囲でバージョンアップする、という指定もできます。


が、普通の開発では使わない気がします。
テスト後に勝手にバージョンアップされたら悲惨です。
基本は明示的にバージョン指定を行っておくものだと思います。

scope

この値でどのスコープでライブラリが必要かを指定します。

  • compile 常にクラスパスに追加し、配布物に含める。デフォルト値。
  • provided コンパイル時に必要な場合。配布物には含めない。Servlet APIなど。
  • runtime コンパイル時に不要で、実行時に必要な場合。配布物には含めない。JDBCドライバなど。
  • test テスト実行時にクラスパスに追加する。JUnitなど。
  • system スコープとしてはcompileと同一。ローカルの別の場所にあるライブラリをsystemPathタグで明示的に指定する。
  • import Maven2.0.9以降の新機能。dependencyManagementを使ってごにょごにょやるらしい。省略。


ここら辺は自身がないので間違っているかもしれないので、詳しくはDependency Scopeを参照のこと。

Maven Repositoryで見つからないライブラリ

DjUnit等のライブラリのように、Maven Repositoryに無いライブラリについては、以下のどちらかの対応をします。

ローカルリポジトリに入れる

mvnコマンドでライブラリを明示的に登録させます。

mvn install:install-file
    -Dfile=${JARファイルのパス}
    -DgroupId=${groupId}
    -DartifactId=${artifactId}
    -Dversion=0.8.3
    -Dpackaging=jar
    -DgeneratePom=true

artifactIdとgroupIdの値はpom.xmlと一致させればいいので何でもよいですが、命名規則は合わせた方がよいと思います。

ちなみに、DjUnitを登録する時はこんなコマンドで登録しました。

mvn install:install-file \
    -Dfile=C:\apache-maven-2.0.9\install-lib\djunit.jar \
    -DgroupId=jp.co.dgic \
    -DartifactId=djunit \
    -Dversion=0.8.3 \
    -Dpackaging=jar \
    -DgeneratePom=true
社内用リポジトリを作る

ローカルリポジトリの場合、プログラマの環境ごとに設定してもらう必要があるため、複数人で開発をしていると破綻します。
その場合、社内用リポジトリを作ることで一元管理ができます。
社内リポジトリの作成はちょっと大変そうなので、そのうちやります。

最後に

エラーが発生した場合

mvnコマンドに-Xオプションを付けて実行するとデバッグモードになるので、わかるかもしれません。