W3docs

Java Maven pom.xml

Il Project Object Model di Maven — struttura di pom.xml, coordinate, proprietà ed ereditarietà.

Il pom.xml è il cuore di qualsiasi progetto Maven. POM sta per Project Object Model — un singolo file XML che dichiara cosa è il tuo progetto (la sua identità), di cosa ha bisogno (le sue dipendenze) e come costruirlo (plugin e configurazione). Maven legge questo file, scarica tutto ciò a cui fa riferimento da un repository ed esegue la build. Mentre un progetto improvvisato disperde queste informazioni tra script shell e una cartella lib/ piena di JAR copiati a mano, Maven le raccoglie tutte in un unico documento dichiarativo e sotto controllo di versione.

Questo capitolo percorre la struttura del POM pezzo per pezzo: lo scheletro minimale, le coordinate GAV che identificano ogni artefatto, come funzionano le dipendenze e gli scope, le proprietà per evitare duplicazioni di versioni e l'ereditarietà attraverso un POM genitore. Se sei nuovo a Maven, inizia con l'introduzione a Maven; per le fasi di build che il POM gestisce, consulta il ciclo di vita della build Maven.

Il POM minimale

Ogni POM è un documento XML con radice nell'elemento <project> con lo schema Maven 4.0.0. Il POM minimo funzionale dichiara la sua versione del modello e le sue coordinate — i quattro valori che identificano l'artefatto:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.w3docs</groupId>
  <artifactId>shop-api</artifactId>
  <version>1.4.0</version>
  <packaging>jar</packaging>
</project>

<modelVersion> è sempre 4.0.0 — è la versione del formato POM, non del tuo codice. Lasciala esattamente come mostrato.

Coordinate: groupId, artifactId, version

Un artefatto Maven è identificato dalle sue coordinate GAV. Ogni dipendenza che aggiungi viene nominata dagli stessi tre (a volte quattro) valori, quindi vale la pena impararli con precisione:

ElementoSignificatoConvenzione
groupIdL'organizzazione o il namespaceDNS inverso, es. com.google.code.gson
artifactIdIl nome del progetto all'interno del gruppoMinuscolo, con trattini, es. shop-api
versionIl rilascio di questo artefattoSemantica, es. 1.4.0; -SNAPSHOT per build in corso
packagingIl tipo di outputjar (predefinito), war, pom

Insieme, groupId:artifactId:version è globalmente unico. È ciò che Maven usa per individuare un JAR in un repository e per nominare l'artefatto prodotto dalla build. Una versione che termina in -SNAPSHOT (es. 1.5.0-SNAPSHOT) è una build mutabile e in sviluppo che Maven potrebbe riscaricare; una versione senza questo suffisso è considerata immutabile.

Dichiarare le dipendenze

Le dipendenze vengono elencate sotto <dependencies>, ognuna come blocco <dependency> che fornisce le coordinate di una libreria necessaria. Maven le risolve — e le loro dipendenze, transitivamente — da un repository (Maven Central per impostazione predefinita):

<dependencies>
  <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
  </dependency>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Lo <scope> controlla quando una dipendenza è nel classpath. compile (il valore predefinito) significa ovunque; test significa solo durante la compilazione e l'esecuzione dei test, quindi JUnit non viene mai incluso nel JAR. Altri scope includono provided (fornito dal runtime, es. una servlet API) e runtime (necessario per l'esecuzione ma non per la compilazione, es. un driver JDBC). La risoluzione transitiva, i conflitti di versione e le regole degli scope sono trattati in dettaglio in dipendenze Maven.

Proprietà: non ripetere le versioni

L'elemento <properties> definisce variabili riutilizzabili, referenziate altrove con la sintassi ${name}. L'idioma consiste nel fissare ogni versione di libreria una volta sola in cima, così gli aggiornamenti avvengono in un unico punto:

<properties>
  <maven.compiler.release>21</maven.compiler.release>
  <junit.version>5.10.2</junit.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
  </dependency>
</dependencies>

maven.compiler.release è una proprietà ben nota che indica al plugin del compilatore quale versione di Java usare come target — più pulita rispetto alla configurazione manuale del plugin. Quando Maven legge il POM, interpola ogni segnaposto ${...}, sostituendo il valore della proprietà prima di risolvere qualsiasi cosa.

Ereditarietà con un POM genitore

I POM formano una gerarchia. Un elemento <parent> fa ereditare a un progetto le coordinate, le proprietà e la gestione delle dipendenze da un altro POM. Il parent starter di Spring Boot è l'esempio classico — fissa un insieme coerente di versioni di librerie in modo da poter omettere <version> per le dipendenze gestite:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.3.2</version>
</parent>

<dependencies>
  <dependency>
    <!-- version omitted: inherited from the parent's dependencyManagement -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

Una build multi-modulo usa lo stesso meccanismo in modo inverso: un POM aggregatore con <packaging>pom</packaging> elenca i <modules>, e ogni figlio lo nomina come <parent>. La configurazione condivisa vive in un unico posto; i figli rimangono snelli.

Un esempio pratico: leggere un POM come farebbe Maven

Un pom.xml è semplice XML, quindi possiamo analizzarne uno con il DOM API integrato del JDK e percorrerne la struttura esattamente come farebbe Maven — leggendo le coordinate, le proprietà e ciascuna dipendenza, interpolando a mano un segnaposto ${...}. (Maven stesso è uno strumento di build, non una libreria nel classpath qui, ma questo mostra il modello su cui opera.)

java— editable, runs on the server

Cosa ricavare dall'esecuzione:

  • La modelVersion viene stampata come 4.0.0 — la costante che ogni POM contiene. Identifica il formato del POM, non il tuo progetto, e Maven rifiuterebbe un POM che la omette.
  • Le coordinate risultano com.w3docs:shop-api:1.4.0, la tripla GAV nella sua forma canonica groupId:artifactId:version. Questa singola stringa è il modo in cui Maven identifica sia l'artefatto prodotto dalla build sia ogni dipendenza che risolve.
  • Il packaging viene letto come jar, il tipo di output predefinito. Se fosse stato pom, questo sarebbe un progetto aggregatore/genitore che non produce alcun JAR proprio.
  • La proprietà junit.version si è risolta in 5.10.2, e il segnaposto ${junit.version} della dipendenza JUnit è stato interpolato allo stesso valore — esattamente la sostituzione che Maven esegue affinché una versione sia dichiarata in un unico posto e riutilizzata.
  • La scansione delle dipendenze ha riportato due dipendenze e le ha stampate ciascuna con il proprio scope: Gson è impostato su compile per impostazione predefinita (nessun elemento <scope>, quindi è in ogni classpath), mentre JUnit mostra scope=test, mantenendolo fuori dall'artefatto distribuito.

Pratica

Pratica
In un pom.xml, qual è lo scopo dei tre elementi groupId, artifactId e version insieme?
In un pom.xml, qual è lo scopo dei tre elementi groupId, artifactId e version insieme?
Was this page helpful?