EclipseでWebアプリを作っていて別プロジェクトを参照している場合の注意点

長いタイトルの割には伝わりづらいw

ええと、Webアプリsample-webを作っているんだけど、ユーティリティ関連は別プロジェクトとしてsample-commonに切り出している。
で、sample-webはsample-commonを参照しているという状況です。かなりありがちだと思います。DBアクセスも外だししてバッチとWebで共有したりするでしょう。

sample-common側のソースは下記で

package common;

public class Greet {

	public static String greet() {
		return "hello";
	}
}

sample-web側はこんな感じ。

package hello;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import common.Greet;

public class HelloServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter writer = response.getWriter();
		writer.println(Greet.greet());
	}

}

Eclipse3.5のプロジェクトはこんな感じ。

ビルドパスはこう

この状況でWTPを起動(APサーバはTomcat6)してHelloServletにアクセスしても下記のように例外が発生します。Greetが見つからんと。

致命的: サーブレット HelloServlet のServlet.service()が例外を投げました
java.lang.ClassNotFoundException: common.Greet
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
at hello.HelloServlet.doGet(HelloServlet.java:19)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:637)

僕は長いことこれはできるもんだと思ってたんですが、そうではなかったようです。Mavenからプロジェクト作ったときは挙動は怪しいながらもできていた記憶が。。。

sample-common側をいちいちjarにしてsample-webのWEB-INF/libに突っ込むのは面倒です。そういうのも見たことありますが。。。

悩んでいたら、同僚が解決策を教えてくれました。sample-webのプロジェクトプロパティの「Java EE Module Dependency」でsample-commonにチェックすればOKです。

OKなのですが、、、

にあるようにsample-commonにMETA-INFができてTomcat関連のjarがビルドパスに追加されます。.projectも変わるし、.settingsにもWTP関連の設定が追加されます。.classpathが変わるのはちょっと微妙。

ただEclipse3.6だと変更と改善?がされてます。

sample-webのプロジェクトプロパティのDeployment Assemblyからsample-commonを追加します。Java EE Module Dependencyは無くなっています。

Eclipse上はこう。

sample-commonの.classpathが追加されますが、Tomcatは入ってこないです。

ともあれ、すごくありがちでハマりそうなんですが、ネットには情報見当たらなかったな。1つのプロジェクトでは問題無くても複数のプロジェクトだと考慮すべき点が出てきますね。

かといって全部1つのプロジェクトにしてしまうとそれはそれで依存関係が密になって一つの修正がどこに影響するかわからない。プロジェクトが多すぎるのも大変ですが、、、うーん、いろいろと難しいですね。