1. モジュール化プロジェクトのビルド: 基本原則
コンパイラとモジュールパス (module-path)
モジュール登場以前は、アプリケーションは classpath(Java がクラスを探すためのディレクトリや JAR の単なるリスト)でコンパイル/実行されていました。モジュールシステムでは新たに module-path が加わりました。いまやコンパイラと JVM は、クラスの所在だけでなく、それらがどのモジュールに属するか、どんな依存関係を持つか、どのパッケージをエクスポートしているかも把握する必要があります。
重要なポイント:
- モジュール化プロジェクトでは --module-path を -classpath の代わりに使います。
- コンパイラと JVM は、アプリケーションに必要なすべてのモジュール(およびその依存関係)を可視化できる必要があります。
例: モジュールを手動でコンパイル
たとえば、core と app という 2 つのモジュールがあり、app が core に依存しているとします。
ディレクトリ構成:
project-root/
core/
src/
main/
java/
module-info.java
com/example/core/...
app/
src/
main/
java/
module-info.java
com/example/app/...
手動コンパイル (デモ):
# まず core をコンパイルする
javac -d out/core core/src/main/java/module-info.java core/src/main/java/com/example/core/*.java
# 次に app。module-path で core を指定してコンパイル
javac --module-path out/core -d out/app app/src/main/java/module-info.java app/src/main/java/com/example/app/*.java
実行:
java --module-path out/core:out/app -m app/com.example.app.Main
実プロジェクトでは手作業は不要です — Maven/Gradle や IDE を使いましょう。
2. Maven: マルチモジュールプロジェクトのビルド
Maven におけるマルチモジュールプロジェクトの構成
Maven は長年にわたり複数モジュール(サブモジュール)構成をサポートしています。Java のモジュールシステムが登場してからは、これらの「Maven のモジュール」が Java モジュールと一致することが多いですが、必ずしもそうとは限りません。Maven モジュールは単なるサブプロジェクトであり、Java モジュールは module-info.java に記述されたものを指します。通常は 1 つの Maven モジュール = 1 つの Java モジュールです。
典型的な構成:
myproject/
pom.xml # Parent POM
core/
pom.xml # core モジュール
src/main/java/
module-info.java
com/example/core/...
app/
pom.xml # app モジュール
src/main/java/
module-info.java
com/example/app/...
親 POM の例 (myproject/pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>app</module>
</modules>
</project>
core モジュールの POM の例 (core/pom.xml):
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>core</artifactId>
<dependencies>
<!-- ここに依存関係(他のモジュールや外部ライブラリなど)を追加できます -->
</dependencies>
</project>
app モジュールの POM の例 (app/pom.xml):
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>app</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
重要:
- app に core が必要な場合、app モジュールの module-info.java に requires core; を記述する必要があります。
- <dependency> と <module> を正しく記述していれば、Maven が依存関係を解決してくれます。
Maven は module-info.java をどう扱うか
- Maven は module-info.java を他のクラスと一緒に自動的にコンパイルします。
- モジュールの依存関係がある場合、Maven はコンパイルと実行時にそれらを module-path に追加します。
- 古いプラグインや Java 9 未満を使っていると、モジュールシステムは動作しません。
Maven 経由でモジュール化アプリを実行する
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<release>21</release> <!-- あるいは使用している Java バージョン -->
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>com.example.app.Main</mainClass>
<commandlineArgs></commandlineArgs>
</configuration>
</plugin>
</plugins>
</build>
mvn clean install
mvn -pl app exec:java
Maven とモジュール使用時のよくある誤り
エラー: 「module not found」。 正しい module-path を指定していないか、依存アーティファクトのための <dependency> が記述されていません。
モジュール名の重複。 プロジェクト内に同名のモジュールが 2 つあってはなりません(例: 2 つの module core)。
exports/requires の不足。 パッケージをエクスポート(exports)していない、または依存(requires)を宣言していない場合、コンパイルエラーになります。
classpath と module-path の混在。 モジュールをサポートしない古いプラグイン/設定は使わないでください。予期しないエラーの原因になります。
3. Gradle: マルチモジュールプロジェクトのビルド
Gradle プロジェクトの構成
myproject/
settings.gradle
build.gradle
core/
build.gradle
src/main/java/module-info.java
src/main/java/com/example/core/...
app/
build.gradle
src/main/java/module-info.java
src/main/java/com/example/app/...
settings.gradle
rootProject.name = 'myproject'
include 'core', 'app'
build.gradle(ルート)
subprojects {
apply plugin: 'java'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21) // もしくは使用している Java のバージョン
}
}
repositories {
mavenCentral()
}
}
core 用の build.gradle
plugins {
id 'java'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
app 用の build.gradle
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
dependencies {
implementation project(':core')
}
application {
mainModule = 'app' // あなたの Java モジュール名
mainClass = 'com.example.app.Main'
}
ビルドと実行
./gradlew build
./gradlew :app:run
Gradle は module-info.java を検出すると module-path を自動的に解決します。もしうまく動作しない場合は、Gradle 本体とプラグインのバージョンが十分に新しいか確認してください。
4. IntelliJ IDEA: モジュール化プロジェクトの作成と設定
モジュール化プロジェクトの作成
- File → New → Project → Java → 「Create module-info.java」を有効化。
- マルチモジュールプロジェクトの場合: File → New → Module — プロジェクトに新しいモジュールを追加します。
- Maven/Gradle を使う場合は、pom.xml または build.gradle でプロジェクトをインポートするだけです。
IDEA での構成表示
- Project View では、各モジュールが別のブランチとして表示されます。
- 各モジュールには独自の module-info.java とソースがあります。
- IDEA は、どのモジュールがどのパッケージをエクスポート/要求しているか(exports/requires)を示してくれます。
- パッケージのエクスポートや依存宣言を忘れている場合、IDEA がエラーとしてハイライトします。
module-path の確認、main クラスの実行
- Run/Debug Configurations で次を指定します:
- Main class(例: com.example.app.Main)
- Module(例: app)
- IDEA が module-path を自動で処理します。
- Maven/Gradle から実行する場合は、対応する設定を使用してください(例: app [run])。
外部モジュールとライブラリのインポート
- 外部ライブラリを使う場合(例: requires java.sql; やサードパーティの JAR)— Maven/Gradle で依存関係を追加します。
- ライブラリがモジュール化されていない(module-info.java がない)場合は、自動的に「unnamed module」に追加されます(多くのライブラリではこれで問題ありません)。
5. 実践: 簡単なマルチモジュールプロジェクトを作る
ステップ 1. プロジェクト構成の作成
myproject/
core/
src/main/java/module-info.java
src/main/java/com/example/core/HelloService.java
app/
src/main/java/module-info.java
src/main/java/com/example/app/Main.java
HelloService.java(core):
package com.example.core;
public class HelloService {
public String getHello() {
return "core モジュールからの挨拶!";
}
}
module-info.java(core):
module core {
exports com.example.core;
}
Main.java(app):
package com.example.app;
import com.example.core.HelloService;
public class Main {
public static void main(String[] args) {
HelloService service = new HelloService();
System.out.println(service.getHello());
}
}
module-info.java(app):
module app {
requires core;
}
ステップ 2. Maven でビルドして実行
プロジェクトのルートに親の pom.xml を作成し、2 つのサブプロジェクト(core/pom.xml、app/pom.xml)を上記のように用意します。app/pom.xml に core への依存を追加します。
mvn clean install
mvn -pl app exec:java
ステップ 3. Gradle でビルドして実行
settings.gradle、ルートの build.gradle、各モジュール用の build.gradle を作成します。app/build.gradle に core への依存と mainClass を設定します。
./gradlew build
./gradlew :app:run
ステップ 4. IntelliJ IDEA でのインポートと実行
- File → Open からプロジェクトのルートを開きます。
- IDEA は Maven/Gradle の構成を認識し、モジュールを作成します。
- 各モジュールで module-info.java を開くと、IDEA はモジュール間の関係を表示します。
- コンテキストメニューから Main.java を実行(「Run Main.main()」)— IDEA が module-path を自動設定します。
6. モジュール化プロジェクトのビルドでよくあるエラー
エラー1: module-path が正しくない。 実行やコンパイル時に「module not found」や「package is not visible」といったメッセージが出る場合、正しい module-path を指定していない、または pom.xml/build.gradle に依存関係を追加し忘れている可能性があります。
エラー2: モジュール名の重複。 プロジェクト内に同名のモジュール(例: 2 つの module core)が存在してはなりません。これはコンパイルエラーにつながります。
エラー3: パッケージの未エクスポート。 クラスが module-info.java の exports でエクスポートされていないパッケージにある場合、たとえそのクラスが public でも他モジュールからは見えません。利用しようとするとコンパイルエラーになります。
エラー4: requires の未宣言。 他モジュールのクラスを使っているのに、module-info.java に requires を記述していない場合、コンパイラがエラーを出します。
エラー5: 外部ライブラリとの非互換。 module-info.java のないライブラリ(「unnamed module」に入る)は通常問題ありませんが、構成によっては追加の設定が必要になることがあります。
エラー6: 別のモジュールから起動している。 IDEA や Maven/Gradle の実行構成で、main クラスやモジュールが誤っているとアプリは起動しません。Main、mainModule/module、使用中のプロファイルを確認してください。
GO TO FULL VERSION