CodeGym /Corsi /JAVA 25 SELF /Build di progetti multi-modulo: Maven, Gradle, IDEA

Build di progetti multi-modulo: Maven, Gradle, IDEA

JAVA 25 SELF
Livello 60, Lezione 4
Disponibile

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.

1
Compito
JAVA 25 SELF, livello 60, lezione 4
Bloccato
Costruzione della fortezza di un progetto multi-modulo 🏰
Costruzione della fortezza di un progetto multi-modulo 🏰
1
Compito
JAVA 25 SELF, livello 60, lezione 4
Bloccato
Avvio del cuore dell'applicazione con Maven ✨
Avvio del cuore dell'applicazione con Maven ✨
1
Sondaggio/quiz
Moduli e struttura del progetto, livello 60, lezione 4
Non disponibile
Moduli e struttura del progetto
Moduli e struttura del progetto
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION