Mavenから開発しやすいEclipseのTomcatプロジェクトを生成する


2011年 02月 27日

EclipseでTomcatを使った開発をしている時に、プロジェクト参照で困ったことはありませんか?
EclipseTipsというすばらしいサイトに、Eclipseでプロジェクト参照した場合の問題点と解決方法が示されています。

かいつまんで問題点を説明するとTomcatはEclipseのプロジェクト参照を考慮することは無いのでTomcatからプロジェクト参照したプロジェクトの成果物が見えるように調整する必要があるという物です。

ここでは備忘録としてmavenを使ってこの問題を解決したプロジェクトファイルを生成する方法を紹介します。

アプリの構成

次の様な単純なマルチモジュールプロジェクトを想定しています。

killer-app/
  |- pom.xml(killer-app-common, killer-app-webがモジュール)
  |- killer-app-common
  |    |- pom.xml
  |- killer-app-web(killer-app-commonを参照)
       |- pom.xml
       |- build.xml(プロジェクト参照を解決するためクラスファイルをコピーするタスクを記述する)
       |- .externalToolBuilders
            |- classescopy.launch(外部ツールとしてbuild.xmlを叩く設定ファイル)

プロジェクト参照の問題を解決する前に

問題を解決する前に、mavenでeclipseのプロジェクトファイルを生成する方法と、mavenで解決した依存関係のjarをsrc/main/webapp/WEB-INF/libにコピーする方法を紹介します。この設定は必ず必要です。
サンプルコードはsastrutsのプロジェクトのひな形の中にmaven-eclipse-pluginから抜粋しました。

92行目からのコードがSysdeo Eclipse Tomcat Launcher pluginを利用したTomcatプロジェクトの.projectファイルを生成する設定です。

92          <plugin>
93            <groupId>org.apache.maven.plugins</groupId>
94            <artifactId>maven-eclipse-plugin</artifactId>
95            <version>2.5.1</version>
96            <configuration>
97              <buildOutputDirectory>src/main/webapp/WEB-INF/classes</buildOutputDirectory>
98              <downloadSources>true</downloadSources>
99              <additionalProjectnatures>
100                <projectnature>com.sysdeo.eclipse.tomcat.tomcatnature</projectnature>
101              </additionalProjectnatures>
102            </configuration>
103          </plugin>

54行目からがclean時にlibの下をきれいに削除する処理、73行目からはビルド前に依存関係のjarをlibの下にコピーする処理です。

54          <plugin>
55            <groupId>org.apache.maven.plugins</groupId>
56            <artifactId>maven-antrun-plugin</artifactId>
57            <version>1.3</version>
58            <executions>
59              <execution>
60                <id>delete-lib-dir</id>
61                <phase>initialize</phase>
62                <configuration>
63                  <tasks>
64                    <delete dir="src/main/webapp/WEB-INF/lib"/>
65                  </tasks>
66                </configuration>
67                <goals>
68                  <goal>run</goal>
69                </goals>
70              </execution>
71            </executions>
72          </plugin>
73          <plugin>
74            <groupId>org.apache.maven.plugins</groupId>
75            <artifactId>maven-dependency-plugin</artifactId>
76            <version>2.0</version>
77            <executions>
78              <execution>
79                <goals>
80                  <goal>copy-dependencies</goal>
81                </goals>
82                <configuration>
83                  <outputDirectory>src/main/webapp/WEB-INF/lib</outputDirectory>
84                  <excludeScope>provided</excludeScope>
85                  <overWriteIfNewer>true</overWriteIfNewer>
86                  <overWriteReleases>true</overWriteReleases>
87                  <overWriteSnapshots>true</overWriteSnapshots>
88                </configuration>
89              </execution>
90            </executions>
91          </plugin>

プロジェクト参照を解決する

弊社のjavaのプロジェクトではEclipseTipsで紹介されている「参照先のクラスファイルを “/WEB-INF/classes/” に配置」する方法を採用しています。(最初はソースリンクを採用していましたが、設定の煩雑さ、ビルド時間の増大が問題になったので切り替えました。)

手順は次の通りです。

  1. クラスファイルをコピーするbuild.xmlを作成
  2. Eclipseの外部ビルダーとして1.で作成したbuild.xmlを呼び出す設定を行う
  3. mavenから外部ビルダーが設定済みのプロジェクトファイルを生成する

1. クラスファイルをコピーするbuild.xmlを作成

まずはクラスファイルをコピーするbuild.xmlを用意します。このbuild.xmlをコンパイル後のタイミングで都度呼び出すことにより、プロジェクト参照の問題を解決します。

<project name="killer-app-web" default="builder" basedir=".">
  <property environment="env" />
  <target name="builder">
    <exec executable="${env.SystemRoot}\System32\xcopy.exe" osfamily="windows" dir="${basedir}">
      <arg value="${basedir}\..\killer-app-common\target\classes"/>
      <arg value="${basedir}\src\main\webapp\WEB-INF\classes"/>
      <arg value="/D"/>
      <arg value="/E"/>
      <arg value="/Y"/>
    </exec>
    <exec executable="cp" osfamily="mac" dir="${basedir}">
      <arg value="-R"/><arg value="-u"/><arg value="-f"/>
      <arg value="${basedir}/../killer-app-common/target/classes"/>
      <arg value="${basedir}/src/main/webapp/WEB-INF/"/>
    </exec>
  </target>
</project>

2. Eclipseの外部ビルダーとして1.で作成したbuild.xmlを呼び出す設定を行う

build.xmlを作成したら、このファイルをEclipseから外部ビルダーとして呼び出す設定を行います。
一旦次のコマンドでプロジェクトファイルを作成してEclipseでプロジェクトを開きましょう。

mvn eclipse:clean eclipse:eclipse

Eclipseでプロジェクトを開けたらGUIで外部ビルダーを登録します。次の手順で設定画面を表示します。

[プロジェクトのプロパティ] -> [Builders] -> [New] -> [AntBuilder]

Mainのタブでは次の設定を行います。

Name: classescopy
Buildfile: ${workspace_loc:/killer-app-web/build.xml}
Base Directory: ${workspace_loc:/killer-app-web/}

Targetsのタブでは次の設定を行います。

After a "Clean": <default target selected>
Manual Build: <default target selected>
Auto Build: <default target selected>
During a "Clean": <Builder is not set to run for this build kind>

MainタブとTargetsタブの設定が完了したら、OKで設定を保存します。
保存すると次のような内容のkiller-app-web/.externalToolBuilders/classescopy.launchというファイルが作成されます。

<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="builder,"/>
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="killer-app-web"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/killer-app-web/build.xml}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/killer-app-web}"/>
</launchConfiguration>

3. mavenから外部ビルダーが設定済みのプロジェクトファイルを生成する

最後にmavenからkiller-app-web/.externalToolBuilders/classescopy.launchが登録済みのプロジェクトファイルを生成できるようにします。外部ビルダーの設定にはmaven-eclipse-pluginのadditionalBuildcommandsという機能を利用します。具体的には次の様な設定を行い、外部のビルダーを設定します。この設定によりプロジェクトファイルに外部ツールとしてkiller-app-web/.externalToolBuilders/classescopy.launchを使う設定が含まれるようになります。

    <configuration>
      <buildOutputDirectory>src/main/webapp/WEB-INF/classes</buildOutputDirectory>
      <downloadSources>true</downloadSources>
      <additionalProjectnatures>
        <projectnature>com.sysdeo.eclipse.tomcat.tomcatnature</projectnature>
      </additionalProjectnatures>
      <additionalBuildcommands>
        <buildCommand>
          <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
          <triggers>auto,full,incremental,</triggers>
          <arguments>
            <LaunchConfigHandle>&lt;project&gt;/.externalToolBuilders/classescopy.launch</LaunchConfigHandle>
        </buildCommand>
      </additionalBuildcommands>
    </configuration>

それでは次のコマンドでプロジェクトファイルを再生成してみましょう。

mvn eclipse:clean eclipse:eclipse

killer-app-web/.projectに次の様な設定が存在すれば成功です。

  <buildSpec>
    <buildCommand>
      <name>org.eclipse.jdt.core.javabuilder</name>
    </buildCommand>
    <buildCommand>
      <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
      <triggers>auto,full,incremental,</triggers>
      <arguments>
        <dictionary>
          <key>LaunchConfigHandle</key>
          <value>&lt;project&gt;/.externalToolBuilders/classescopy.launch</value>
        </dictionary>
      </arguments>
    </buildCommand>
  </buildSpec>

依存するプロジェクトが増えた場合

依存するプロジェクトが増えた場合は、killer-app-web/pom.xmlに新しく依存するプロジェクトを登録し、killer-app-web/build.xmlにそのプロジェクトのクラスファイルをコピーする設定を追加します。
設定したら、プロジェクトファイルを再生成しましょう。

mvn eclipse:clean eclipse:eclispe