1. Збирання модульних проєктів: базові принципи
Компілятор і модульний шлях (module-path)
До появи модулів увесь застосунок компілювався та запускався за допомогою так званого classpath — просто списку каталогів і JAR-файлів, у яких Java шукала класи. У модульній системі з’явився новий гравець — module-path. Тепер компілятор і JVM мають знати не лише, де лежать класи, а й до яких модулів вони належать, які залежності в них є та які пакети експортуються.
Ключовий момент:
- Для модульних проєктів використовуйте --module-path замість -classpath.
- Компілятор і JVM повинні «бачити» усі модулі, які потрібні вашому застосунку (і їхні залежності).
Приклад: ручна компіляція модулів
Припустімо, у вас є два модулі: core і app, де 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 давно підтримує структуру з кількома модулями (submodules). Тепер, із появою модульної системи Java, ці «модулі» Maven часто збігаються з модулями Java, але не завжди: модуль Maven — це просто підпроєкт, а модуль Java — це те, що описано в module-info.java. Зазвичай один модуль Maven = один модуль Java.
Типова структура:
myproject/
pom.xml # Батьківський 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>
Приклад POM для модуля core (core/pom.xml):
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>core</artifactId>
<dependencies>
<!-- Тут можуть бути залежності, наприклад, на інші модулі або сторонні бібліотеки -->
</dependencies>
</project>
Приклад POM для модуля app (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, у module-info.java модуля app має бути requires core;
- Maven сам збере залежності, якщо правильно прописані <dependency> і <module>.
Як 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> для залежного артефакту.
Дублювання імен модулів. У проєкті не повинно бути двох модулів з однаковими іменами (наприклад, два module core).
Відсутність export/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()
}
}
build.gradle для core
plugins {
id 'java'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
build.gradle для app
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-path, якщо виявляє module-info.java. Якщо щось не працює — перевірте, що ви використовуєте актуальну версію 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 і два підпроєкти (core/pom.xml, app/pom.xml) як вище. У app/pom.xml додаємо залежність на core.
mvn clean install
mvn -pl app exec:java
Крок 3. Збирання та запуск через Gradle
Створюємо settings.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: Дублювання імен модулів. У проєкті не повинно бути двох модулів з однаковою назвою (наприклад, два module core). Це призводить до помилки компіляції.
Помилка № 3: Неекспортований пакет. Якщо клас міститься в пакеті, який не експортується через exports у module-info.java, то він буде недоступний іншим модулям, навіть якщо public. Виникне помилка компіляції під час спроби використати такий клас.
Помилка № 4: Неоголошений requires. Якщо модуль використовує класи з іншого модуля, але не вказав requires у module-info.java, компілятор видасть помилку.
Помилка № 5: Несумісність із зовнішніми бібліотеками. Невідповідність модулів і бібліотек без module-info.java (вони потрапляють до «unnamed module») зазвичай не заважає, але в деяких конфігураціях може знадобитися додаткове налаштування.
Помилка № 6: Запуск не з того модуля. У конфігурації запуску IDEA або Maven/Gradle вказано неправильний main-клас або модуль — застосунок не стартує. Перевірте Main, mainModule/module і використаний профіль.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ