Java Maven pom.xml
O Project Object Model do Maven — estrutura do pom.xml, coordenadas, propriedades e herança explicadas.
O pom.xml é o coração de qualquer projeto Maven. POM significa Project Object Model — um único arquivo XML que declara o que é o seu projeto (sua identidade), o que ele precisa (suas dependências) e como construí-lo (plugins e configuração). O Maven lê esse arquivo, baixa tudo o que ele referencia de um repositório e executa o build. Enquanto um projeto improvisado espalha esse conhecimento por scripts shell e uma pasta lib/ com JARs copiados manualmente, o Maven coloca tudo em um documento declarativo e versionado.
Este capítulo percorre a estrutura do POM parte a parte: o esqueleto mínimo, as coordenadas GAV que nomeiam cada artefato, como dependências e escopos funcionam, propriedades para eliminar duplicação de versões e herança por meio de um POM pai. Se você é novo no Maven, comece pela introdução ao Maven; para as fases de build que o POM conduz, consulte o ciclo de vida de build do Maven.
O POM mínimo
Todo POM é um documento XML com raiz em um elemento <project> e o esquema Maven 4.0.0. O menor POM útil declara sua versão de modelo e suas coordenadas — os quatro valores que nomeiam o artefato:
<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 — é a versão do formato do POM, não do seu código. Deixe exatamente como mostrado.
Coordenadas: groupId, artifactId, version
Um artefato Maven é identificado por suas coordenadas GAV. Toda dependência que você adicionar é nomeada pelos mesmos três (às vezes quatro) valores, por isso vale aprendê-los com precisão:
| Elemento | Significado | Convenção |
|---|---|---|
groupId | A organização ou namespace | DNS reverso, ex.: com.google.code.gson |
artifactId | O nome do projeto dentro do grupo | Minúsculas com hífens, ex.: shop-api |
version | A versão deste artefato | Semântica, ex.: 1.4.0; -SNAPSHOT para builds em andamento |
packaging | O tipo de saída | jar (padrão), war, pom |
Juntos, groupId:artifactId:version é globalmente único. É o que o Maven usa para localizar um JAR em um repositório e para nomear o artefato que o seu build produz. Uma versão terminada em -SNAPSHOT (ex.: 1.5.0-SNAPSHOT) é um build mutável em desenvolvimento que o Maven pode re-baixar; uma versão simples é tratada como imutável.
Declarando dependências
As dependências são listadas em <dependencies>, cada uma sendo um bloco <dependency> com as coordenadas de uma biblioteca necessária. O Maven as resolve — e as dependências delas, transitivamente — a partir de um repositório (Maven Central por padrão):
<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>O <scope> controla quando uma dependência está no classpath. compile (o padrão) significa em todos os lugares; test significa apenas durante a compilação e execução de testes, então o JUnit nunca vai dentro do seu JAR. Outros escopos incluem provided (fornecido pelo ambiente de execução, ex.: uma API de servlet) e runtime (necessário para executar, mas não para compilar, ex.: um driver JDBC). A resolução transitiva, conflitos de versão e regras de escopo são abordados em profundidade em dependências Maven.
Propriedades: não repita versões
O elemento <properties> define variáveis reutilizáveis, referenciadas em outros lugares com a sintaxe ${nome}. O idioma é fixar cada versão de biblioteca uma vez no topo para que atualizações ocorram em um ú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 é uma propriedade bem conhecida que informa ao plugin compilador qual versão do Java deve ser o alvo — mais limpo do que configurar o plugin manualmente. Quando o Maven lê o POM ele interpola cada marcador ${...}, substituindo o valor da propriedade antes de resolver qualquer coisa.
Herança com um POM pai
Os POMs formam uma hierarquia. Um elemento <parent> faz um projeto herdar coordenadas, propriedades e gerenciamento de dependências de outro POM. O parent starter do Spring Boot é o exemplo clássico — ele fixa um conjunto consistente de versões de bibliotecas para que você possa omitir <version> nas dependências gerenciadas:
<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>Um build multi-módulo usa o mesmo mecanismo de forma inversa: um POM agregador com <packaging>pom</packaging> lista os <modules>, e cada filho o nomeia como <parent>. A configuração compartilhada fica em um lugar; os filhos permanecem pequenos.
Um exemplo trabalhado: lendo um POM como o Maven faz
Um pom.xml é apenas XML, então podemos analisar um com a API DOM nativa do JDK e percorrer sua estrutura exatamente como o Maven faria — lendo as coordenadas, as propriedades e cada dependência, enquanto interpolamos um marcador ${...} manualmente. (O Maven em si é uma ferramenta de build, não uma biblioteca no classpath aqui, mas isso mostra o modelo sobre o qual ele opera.)
O que extrair da execução:
- O
modelVersionfoi impresso como4.0.0— a constante que todo POM carrega. Ela identifica o formato do POM, não o seu projeto, e o Maven rejeitaria um POM que a omitisse. - As coordenadas saíram como
com.w3docs:shop-api:1.4.0, o triplo GAV na sua forma canônicagroupId:artifactId:version. Essa única string é como o Maven nomeia tanto o artefato que este build produz quanto cada dependência que ele resolve. - O
packagingfoi lido de volta comojar, o tipo de saída padrão. Se fossepom, este seria um projeto agregador/pai que não produz nenhum JAR próprio. - A propriedade
junit.versionresolveu para5.10.2, e o marcador${junit.version}da dependência do JUnit foi interpolado para esse mesmo valor — exatamente a substituição que o Maven realiza para que uma versão seja declarada em um lugar e reutilizada. - A varredura de dependências reportou duas dependências e imprimiu cada uma com seu escopo: Gson teve como padrão
compile(sem elemento<scope>, portanto está em todo classpath), enquanto o JUnit mostrouscope=test, mantendo-o fora do artefato distribuído.