1. Build di progetti modulari: principi di base
Compilatore e percorso dei moduli (module-path)
Prima dell’introduzione dei moduli, l’intera applicazione veniva compilata ed eseguita tramite il cosiddetto classpath — un semplice elenco di directory e file JAR in cui Java cercava le classi. Nel sistema modulare è comparso un nuovo attore — module-path. Ora il compilatore e la JVM devono sapere non solo dove si trovano le classi, ma anche a quali moduli appartengono, quali dipendenze hanno e quali package vengono esportati.
Punto chiave:
- Per i progetti modulari usate --module-path invece di -classpath.
- Il compilatore e la JVM devono vedere tutti i moduli necessari alla vostra applicazione (e le loro dipendenze).
Esempio: compilazione manuale dei moduli
Supponiamo che abbiate due moduli: core e app, dove app dipende da core.
Struttura delle directory:
project-root/
core/
src/
main/
java/
module-info.java
com/example/core/...
app/
src/
main/
java/
module-info.java
com/example/app/...
Compilazione manuale (dimostrazione):
# Per prima cosa compiliamo core
javac -d out/core core/src/main/java/module-info.java core/src/main/java/com/example/core/*.java
# Poi app, specificando module-path verso core
javac --module-path out/core -d out/app app/src/main/java/module-info.java app/src/main/java/com/example/app/*.java
Esecuzione:
java --module-path out/core:out/app -m app/com.example.app.Main
Nei progetti reali non è necessario farlo a mano — usate Maven/Gradle o l’IDE.
2. Maven: build di progetti multi-modulo
Struttura di un progetto multi-modulo in Maven
Maven supporta da tempo una struttura con più moduli (submodules). Con l’introduzione del sistema modulare di Java, questi “moduli” di Maven spesso coincidono con i moduli di Java, ma non sempre: un modulo Maven è semplicemente un sotto-progetto, mentre un modulo Java è ciò che è descritto in module-info.java. Di solito un modulo Maven = un modulo Java.
Struttura tipica:
myproject/
pom.xml # Parent POM
core/
pom.xml # Modulo core
src/main/java/
module-info.java
com/example/core/...
app/
pom.xml # Modulo app
src/main/java/
module-info.java
com/example/app/...
Esempio di parent 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>
Esempio di POM per il modulo core (core/pom.xml):
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>core</artifactId>
<dependencies>
<!-- Qui possono esserci dipendenze, ad esempio verso altri moduli o librerie di terze parti -->
</dependencies>
</project>
Esempio di POM per il modulo 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>
Importante:
- Se in app è richiesto core, in module-info.java del modulo app deve esserci requires core;
- Maven risolverà automaticamente le dipendenze, se sono configurati correttamente <dependency> e <module>.
Come Maven tiene conto di module-info.java
- Maven compila automaticamente module-info.java insieme alle altre classi.
- Se avete dipendenze modulari, Maven le aggiungerà al module-path in fase di compilazione ed esecuzione.
- Se usate plugin obsoleti o Java sotto la versione 9 — il sistema modulare non funzionerà.
Esecuzione di un’applicazione modulare tramite Maven
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<release>21</release> <!-- oppure la vostra versione di 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
Errori tipici con Maven e i moduli
Errore: «module not found». Non è stato indicato correttamente il module-path oppure manca il <dependency> per l’artefatto dipendente.
Duplicazione dei nomi dei moduli. Nel progetto non devono esserci due moduli con lo stesso nome (ad esempio, due module core).
Mancanza di export/requires. Se avete dimenticato di esportare un package (exports) o dichiarare una dipendenza (requires), si verificherà un errore di compilazione.
Mescolare classpath e module-path. Non usate plugin/configurazioni obsolete che non supportano i moduli: porta a errori imprevedibili.
3. Gradle: build di progetti multi-modulo
Struttura del progetto con 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 (root)
subprojects {
apply plugin: 'java'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21) // oppure la vostra versione di Java
}
}
repositories {
mavenCentral()
}
}
build.gradle per core
plugins {
id 'java'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
build.gradle per app
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
dependencies {
implementation project(':core')
}
application {
mainModule = 'app' // Nome del vostro modulo Java
mainClass = 'com.example.app.Main'
}
Build ed esecuzione
./gradlew build
./gradlew :app:run
Gradle individua automaticamente il module-path se trova module-info.java. Se qualcosa non funziona — verificate di usare una versione aggiornata di Gradle e dei plugin.
4. IntelliJ IDEA: creazione e configurazione di un progetto modulare
Creazione di un progetto modulare
- File → New → Project → Java → abilitate «Create module-info.java».
- Per un progetto multi-modulo: File → New → Module — aggiungete nuovi moduli al progetto.
- Se usate Maven/Gradle — importate semplicemente il progetto tramite pom.xml o build.gradle.
Struttura in IDEA
- In Project View ogni modulo è visualizzato come un ramo separato.
- In ogni modulo — il proprio module-info.java, i propri sorgenti.
- IDEA suggerisce quali moduli esportano/richiedono quali package (exports/requires).
- Se avete dimenticato di esportare un package o dichiarare una dipendenza — IDEA evidenzierà l’errore.
Verifica del module-path, esecuzione della classe main
- In Run/Debug Configurations specificate:
- Main class (ad esempio, com.example.app.Main)
- Module (ad esempio, app)
- IDEA gestirà da sola il module-path.
- Se eseguite tramite Maven/Gradle — usate le relative configurazioni (ad esempio, app [run]).
Import di moduli e librerie di terze parti
- Per lavorare con librerie esterne (ad esempio, requires java.sql; oppure JAR di terze parti) — aggiungete la dipendenza tramite Maven/Gradle.
- Se la libreria non è modulare (non ha module-info.java), verrà automaticamente aggiunta all’«unnamed module» (va bene per la maggior parte delle librerie).
5. Pratica: creazione di un semplice progetto multi-modulo
Passo 1. Creiamo la struttura del progetto
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 "Ciao dal modulo 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;
}
Passo 2. Build ed esecuzione con Maven
Nella radice del progetto creiamo il parent pom.xml e due sotto-progetti (core/pom.xml, app/pom.xml) come sopra. In app/pom.xml aggiungiamo la dipendenza da core.
mvn clean install
mvn -pl app exec:java
Passo 3. Build ed esecuzione con Gradle
Creiamo settings.gradle, il build.gradle root e uno per ciascun modulo. In app/build.gradle specifichiamo la dipendenza da core e la mainClass.
./gradlew build
./gradlew :app:run
Passo 4. Import ed esecuzione in IntelliJ IDEA
- Apriamo la radice del progetto tramite File → Open.
- IDEA riconosce la struttura Maven/Gradle e crea i moduli.
- In ciascun modulo potete aprire module-info.java, IDEA mostrerà le relazioni tra i moduli.
- Eseguiamo Main.java dal menu contestuale («Run Main.main()») — IDEA imposterà automaticamente il module-path.
6. Errori tipici durante il build di progetti modulari
Errore n. 1: module-path errato. Se in fase di esecuzione o compilazione compare un messaggio come «module not found» o «package is not visible», molto probabilmente non avete indicato correttamente il module-path o avete dimenticato di aggiungere la dipendenza in pom.xml/build.gradle.
Errore n. 2: duplicazione dei nomi dei moduli. Nel progetto non devono esserci due moduli con lo stesso nome (ad esempio, due module core). Questo porta a un errore di compilazione.
Errore n. 3: package non esportato. Se una classe si trova in un package che non è esportato tramite exports in module-info.java, non sarà accessibile da altri moduli, anche se è public. Si verificherà un errore di compilazione tentando di usare tale classe.
Errore n. 4: requires non dichiarato. Se un modulo usa classi di un altro modulo, ma non ha specificato requires in module-info.java, il compilatore segnalerà un errore.
Errore n. 5: incompatibilità con librerie esterne. Il mismatch tra moduli e librerie senza module-info.java (che finiscono nell’«unnamed module») di solito non è un problema, ma in alcune configurazioni può essere necessaria una configurazione aggiuntiva.
Errore n. 6: esecuzione dal modulo sbagliato. Nella configurazione di esecuzione di IDEA o di Maven/Gradle è stata indicata una main class o un modulo non corretti — l’applicazione non parte. Verificate Main, mainModule/module e il profilo utilizzato.
GO TO FULL VERSION