NetBeansのMaven2が優等生過ぎるのでEclipse登場でござる、の巻

先週辺りからNetBeansMaven2サポートの機能を色々と調べているのですが、サポートが完璧すぎる故にはまった変な所があるので紹介します。

ビルドの仕組み

EclipseもそうですがNetBeansでもいわゆるインクリメンタルビルドが行われるため、基本的にはソースコードを保存した瞬間にバックグラウンドでコンパイルされます。これに対して明示的にビルドする場合の挙動が違います。Eclipseは専用のコンパイラでビルドするのに対し、NetBeansではデフォルトでAntのビルドが実行されます。プロジェクトの作成時に設定はAntの設定ファイルとして保存されるようになり、コマンドラインからAntビルドしている状況と同じになるわけです。
Maven2プロジェクトの場合、Ant用の設定ファイルは作られません。代わりにpom.xmlが設定ファイルとなります。そして、ビルドに関してはMaven2のビルドが使用されます。これは予想される正しい形でしょう。

実行

問題となるのが実行時の挙動です。
Maven2は様々な処理を自動化することのできるツールであるため、execという外部プロセスを実行するプラグインも提供されています。ビルド後にあるスクリプト(シェル等)を実行させるなどの使い方や、ビルド後に自動的にビルドしたプログラムを走らせるような使い方ができるわけです。
ここで問題となったのが、NetBeansMaven2プロジェクトを実行する場合の挙動です。当然、execプラグインを使えば実現できますし、Maven2サポートを謳っている以上は自然な挙動かも知れません。ところが、実行時にスレッドを起動し待機するようプログラム*1を起動すると、実行したプロセスを止める手段がなくなります。これは困ったもので、Windowsであればタスクマネージャからjava.exeを殺す以外なくなります。
例えばMaven2プロジェクトを作成して次のようなコードを実行すると、実行をとめることができなくなります。

public class App {

   public static void main(String[] args) {
       Executors.newSingleThreadExecutor().submit(new Runnable() {

           public void run() {
               while (true) {
                   try {
                       System.out.println("!");
                       Thread.sleep(1000);
                   } catch (InterruptedException ex) {
                       ex.printStackTrace();
                   }
               }
           }
       });
   }
}

対策

色々と対策を練ってみたのですが、解決できませんでした(T_T
苦肉の策として考えたのは、NetBeansMaven2プロジェクトを作成し開発はEclipseで行うという方法ですw

mvn eclipse:eclipse

Maven2にあるeclipseプラグインを使うと、Maven2プロジェクトにEclipseの設定ファイルを追加し、Eclipseからインポートできるようになります。

mvn eclipse:eclipse

これで開発はEclipseでできるようになりました。

mvn eclipse:clean

Eclipseのプロジェクト設定ファイルをまとめて消すには、eclipse:cleanを使用します。

mvn eclipse:clean

マルチプロジェクトの問題

Maven2ではプロジェクトの親子関係を定義することで共通のライブラリを読み込んだり、共通の設定(例:コンパイルレベルや文字コード)をすることができます。そのようなマルチプロジェクトの場合、親プロジェクトでmvn eclipse:eclipseを使えば、すべてのプロジェクトがeclipseプロジェクトになります。
この時、依存するプロジェクトに関してはEclipseの「依存プロジェクト」に設定されますが、プロジェクト名とプロジェクトディレクトリが一致していなければなりません。例えば「s4-common」というプロジェクトIDがあったとして、プロジェクトディレクトリが「common」では依存プロジェクトがないとエラーになってしまいます。
回避方法としては名前を合わせる*2か、オプションの「useProjectReferences」をfalseに設定します。このオプションは依存プロジェクトを設定する代わりに、依存ライブラリとしてローカルリポジトリを参照する設定です。

mvn eclipse:eclipse -Declipse.useProjectReferences=false

尚、どうもバグがあるらしく親プロジェクトでこのオプションを指定しても子プロジェクトに反映されません。したがって各プロジェクトのディレクトリでコマンドを実行することが必要です。

まとめ

実行はMaven2使わなくていいです・・・。
開発時に実行する場合などはMaven2で重量なプロセスを動かすよりもさくっと動いて欲しいものです。Maven2のexecプラグインも選択できるのは良いのですが、通常のプロジェクトと同じように動かすことをデフォルトにして欲しいですね。

*1:例えばポートを開けて待ち受けるサーバプログラム

*2:名前の慣習からするとあまり気持ちよくない…