W3docs

Java Maven pom.xml

El modelo de objetos de proyecto Maven — estructura de pom.xml, coordenadas, propiedades y herencia explicadas.

El pom.xml es el corazón de cualquier proyecto Maven. POM significa Project Object Model — un único archivo XML que declara qué es tu proyecto (su identidad), qué necesita (sus dependencias) y cómo construirlo (plugins y configuración). Maven lee este archivo, descarga todo lo que referencia desde un repositorio y ejecuta la construcción. Donde un proyecto ad-hoc dispersa este conocimiento entre scripts de shell y una carpeta lib/ con JARs copiados a mano, Maven lo pone todo en un único documento declarativo y controlado por versiones.

Este capítulo recorre la estructura del POM pieza por pieza: el esqueleto mínimo, las coordenadas GAV que nombran cada artefacto, cómo funcionan las dependencias y los scopes, las propiedades para evitar duplicar versiones y la herencia mediante un POM padre. Si eres nuevo en Maven, comienza con la introducción a Maven; para las fases de construcción que el POM dirige, consulta el ciclo de vida de construcción de Maven.

El POM mínimo

Todo POM es un documento XML con raíz en un elemento <project> con el esquema Maven 4.0.0. El POM más pequeño útil declara su versión de modelo y sus coordenadas — los cuatro valores que nombran el artefacto:

<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> es siempre 4.0.0 — es la versión del formato POM, no de tu código. Déjalo exactamente como se muestra.

Coordenadas: groupId, artifactId, version

Un artefacto Maven se identifica por sus coordenadas GAV. Cada dependencia que añadas se nombra con los mismos tres (a veces cuatro) valores, por lo que vale la pena aprenderlos con precisión:

ElementoSignificadoConvención
groupIdLa organización o espacio de nombresDNS inverso, por ejemplo com.google.code.gson
artifactIdEl nombre del proyecto dentro del grupoMinúsculas con guiones, por ejemplo shop-api
versionLa versión de este artefactoSemántica, por ejemplo 1.4.0; -SNAPSHOT para compilaciones en progreso
packagingEl tipo de salidajar (por defecto), war, pom

En conjunto, groupId:artifactId:version es globalmente único. Es lo que Maven usa para localizar un JAR en un repositorio y nombrar el artefacto que produce tu construcción. Una versión que termina en -SNAPSHOT (por ejemplo 1.5.0-SNAPSHOT) es una compilación mutable en desarrollo que Maven puede volver a descargar; una versión normal se trata como inmutable.

Declarar dependencias

Las dependencias se listan bajo <dependencies>, cada una en un bloque <dependency> que indica las coordenadas de una biblioteca que necesitas. Maven las resuelve — y sus dependencias, transitivamente — desde un repositorio (Maven Central por defecto):

<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>

El <scope> controla cuándo una dependencia está en el classpath. compile (el valor por defecto) significa en todas partes; test significa solo al compilar y ejecutar pruebas, por lo que JUnit nunca se incluye dentro de tu JAR. Otros scopes incluyen provided (suministrado por el runtime, por ejemplo una API de servlet) y runtime (necesario para ejecutar pero no para compilar, por ejemplo un driver JDBC). La resolución transitiva, los conflictos de versiones y las reglas de scope se tratan en profundidad en dependencias de Maven.

Propiedades: no repetir versiones

El elemento <properties> define variables reutilizables, referenciadas en otros lugares con la sintaxis ${name}. El patrón habitual es fijar la versión de cada biblioteca una sola vez en la parte superior para que las actualizaciones ocurran en un único lugar:

<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 es una propiedad conocida que le indica al plugin del compilador qué versión de Java debe ser el objetivo — más limpio que configurar el plugin manualmente. Cuando Maven lee el POM, interpola cada marcador ${...}, sustituyendo el valor de la propiedad antes de resolver cualquier cosa.

Herencia con un POM padre

Los POMs forman una jerarquía. Un elemento <parent> hace que un proyecto herede coordenadas, propiedades y la gestión de dependencias de otro POM. El parent starter de Spring Boot es el ejemplo clásico — fija un conjunto coherente de versiones de bibliotecas para que puedas omitir <version> en las dependencias gestionadas:

<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 construcción multi-módulo usa el mismo mecanismo a la inversa: un POM agregador con <packaging>pom</packaging> lista <modules>, y cada hijo lo nombra como <parent>. La configuración compartida vive en un único lugar; los hijos permanecen pequeños.

Un ejemplo práctico: leer un POM como lo hace Maven

Un pom.xml es simplemente XML, por lo que podemos analizar uno con la API DOM integrada del JDK y recorrer su estructura exactamente como lo haría Maven — leyendo las coordenadas, las propiedades y cada dependencia, mientras interpolamos un marcador ${...} a mano. (Maven en sí es una herramienta de construcción, no una biblioteca en el classpath aquí, pero esto muestra el modelo sobre el que opera.)

java— editable, runs on the server

Qué extraer de la ejecución:

  • La modelVersion se imprimió como 4.0.0 — la constante que lleva todo POM. Identifica el formato del POM, no tu proyecto, y Maven rechazaría un POM que la omitiera.
  • Las coordenadas resultaron ser com.w3docs:shop-api:1.4.0, la tripleta GAV en su forma canónica groupId:artifactId:version. Esta cadena única es la forma en que Maven nombra tanto el artefacto que produce esta construcción como cada dependencia que resuelve.
  • packaging se leyó como jar, el tipo de salida por defecto. Si hubiera sido pom, sería un proyecto agregador/padre que no produce ningún JAR propio.
  • La propiedad junit.version se resolvió a 5.10.2, y el marcador ${junit.version} de la dependencia JUnit fue interpolado a ese mismo valor — exactamente la sustitución que realiza Maven para que una versión se declare en un solo lugar y se reutilice.
  • El recorrido de dependencias reportó dos dependencias e imprimió cada una con su scope: Gson pasó por defecto a compile (sin elemento <scope>, por lo que está en todos los classpaths), mientras que JUnit mostró scope=test, manteniéndolo fuera del artefacto publicado.

Práctica

Práctica
En un pom.xml, ¿cuál es el propósito de los tres elementos groupId, artifactId y version juntos?
En un pom.xml, ¿cuál es el propósito de los tres elementos groupId, artifactId y version juntos?
Was this page helpful?