Java Maven

Na aula de JAR, a Ana compilou, montou o classpath e criou o JAR à mão, com vários comandos. Num projeto de verdade, com dezenas de classes, testes e bibliotecas, isso vira um pesadelo. O Maven é a ferramenta que faz todo esse trabalho com um comando: mvn package.

Você vai aprender
  • O que é o Maven e quais problemas ele resolve (dependências e build padronizado).
  • Criar um projeto com mvn archetype:generate e, também, escrevendo o pom.xml à mão.
  • O pom.xml mínimo para Java 25, linha por linha.
  • A estrutura de pastas padrão (src/main/java, src/test/java).
  • mvn compile, mvn test, mvn package, mvn clean e a pasta target/.
  • O repositório local ~/.m2/repository e como adicionar uma biblioteca.
  • Ler um BUILD FAILURE: erro de compilação, dependência inexistente, pasta errada.

Os exemplos rodam na máquina fictícia da Ana, com Maven 3.10.0 e JDK 25. As saídas do Maven são longas; quando um trecho for repetitivo (como centenas de linhas de download), ele aparece encurtado com … e um aviso.


A ideia: uma receita de bolo que a cozinha entende

Pense numa padaria. Cada confeiteiro tinha o seu jeito de organizar a cozinha, e cada receita dizia "pegue a farinha no armário da esquerda, depois ligue o forno…". Quando alguém novo chegava, levava dias para entender a cozinha do outro.

O Maven é uma cozinha padronizada: a farinha está sempre no mesmo lugar, o forno sempre liga do mesmo jeito. A sua receita (o arquivo pom.xml) só precisa dizer o que é diferente no seu bolo: o nome, a versão, os ingredientes comprados prontos (as dependências). Isso tem até nome: convention over configuration, "convenção em vez de configuração".

O Maven resolve dois problemas:

ProblemaSem MavenCom Maven
Dependências (bibliotecas de outras pessoas)Procurar o JAR na internet, baixar, baixar também os JARs de que ele precisa, montar o -cp à mãoEscrever 5 linhas no pom.xml; o Maven baixa tudo, inclusive as dependências das dependências
Build (compilar, testar, empacotar)javac -d … -cp …, rodar os testes, jar cfe …, cada projeto de um jeitomvn package, igual em qualquer projeto Maven do mundo

Maven é uma palavra do iídiche que quer dizer "especialista, quem acumula conhecimento". O comando é mvn. É a ferramenta de build mais usada em Java; a outra grande é o Gradle.


1. Instalar e conferir

No laboratório da Ana, o Maven já está instalado em /opt/maven. No Ubuntu/Debian, você instalaria com sudo apt install maven (pode vir uma versão mais antiga) ou baixando o .tar.gz do site maven.apache.org e pondo a pasta bin no PATH, do mesmo jeito que o JDK em Instalar no Linux. O Maven precisa de um JDK instalado. Confira:

$ mvn -version
Apache Maven 3.10.0 (c43a36b8d67be7e0805a411bc0898af1a51f5472)
Maven home: /opt/maven
Java version: 25.0.4.1, vendor: Eclipse Adoptium, runtime: /opt/jdk-25
Default locale: pt_BR, platform encoding: UTF-8, time zone: America/Sao_Paulo
OS name: "linux", version: "7.0.0-38-generic", arch: "amd64", family: "unix"

A linha importante é Java version: é o JDK que o Maven vai usar para compilar (o da variável JAVA_HOME). Se aparecer um Java antigo, o seu projeto para Java 25 não compila.


2. Criar um projeto com mvn archetype:generate

Um arquétipo (archetype, "modelo original") é um molde de projeto. O Maven tem um para "aplicativo simples", o maven-archetype-quickstart. Normalmente o comando faz perguntas; com -DinteractiveMode=false ele usa o que você passar e não pergunta nada:

$ mvn archetype:generate -DgroupId=br.com.ana -DartifactId=loja -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DjavaCompilerVersion=25 -DinteractiveMode=false
mvn archetype:generate
Rode o plugin archetype, tarefa (goal, "objetivo") generate. Quase tudo no Maven é feito por plugins.
-DgroupId=br.com.ana
O grupo: quem fez o projeto, normalmente um domínio ao contrário (como os pacotes). Cada -Dnome=valor passa uma configuração.
-DartifactId=loja
O artefato: o nome do projeto. Vira o nome da pasta e do JAR.
-DarchetypeArtifactId=maven-archetype-quickstart
Qual molde usar.
-DarchetypeVersion=1.5
A versão do molde. Sem isso, o Maven usa a versão 1.0, de 2006, que gera um projeto com JUnit 3.
-DjavaCompilerVersion=25
Para qual versão do Java compilar (o molde usa 17 se você não disser).
-DinteractiveMode=false
Não fazer perguntas.

Na primeira vez que você usa o Maven, ele baixa da internet os plugins de que precisa. A saída começa com uma parede de downloads (encurtada aqui: foram 149 arquivos e quase um minuto):

[INFO] Scanning for projects...
[INFO] Loaded 24119 auto-discovered prefixes for remote repository central (prefixes-central.txt)
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/3.5.0/maven-clean-plugin-3.5.0.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/3.5.0/maven-clean-plugin-3.5.0.pom (5.7 kB at 79 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/44/maven-plugins-44.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/44/maven-plugins-44.pom (8.4 kB at 58 kB/s)
…                                                    « mais ~145 downloads

Depois dos downloads vem o que interessa:

[INFO] --- archetype:3.4.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
…                                                    « um aviso [WARNING] sobre o catálogo, que pode ignorar
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.5
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: br.com.ana
[INFO] Parameter: artifactId, Value: loja
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: br.com.ana
…                                                    « outros parâmetros (alguns repetidos)
[INFO] Parameter: javaCompilerVersion, Value: 25
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[WARNING] Don't override file /home/ana/loja/src/main/java/br/com/ana
[WARNING] Don't override file /home/ana/loja/src/test/java/br/com/ana
[WARNING] CP Don't override file /home/ana/loja/.mvn
[INFO] Project created from Archetype in dir: /home/ana/loja
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.181 s
[INFO] Finished at: 2026-10-16T18:24:00-03:00
[INFO] ------------------------------------------------------------------------

Como ler: cada linha começa com o nível da mensagem, [INFO] (informação), [WARNING] (aviso, o build continua) ou [ERROR]. O que decide se deu certo é o fim: BUILD SUCCESS. Os três Don't override file são uma esquisitice dessa versão do molde, mesmo numa pasta nova; não atrapalham.

O que foi criado

$ cd loja
$ find . -type f
./src/test/java/br/com/ana/AppTest.java
./src/main/java/br/com/ana/App.java
./pom.xml
./.mvn/maven.config
./.mvn/jvm.config

O App.java é um "Hello World!" no pacote br.com.ana; o AppTest.java é um teste de exemplo (você vai escrever testes de verdade em Testes com JUnit). A pasta .mvn guarda opções extras do Maven e da JVM para este projeto (os dois arquivos vêm vazios). O pom.xml gerado tem uns 80 linhas, cheio de comentários e versões de plugins. Para entender cada parte, é melhor começar por um pom.xml mínimo, escrito à mão.


3. O pom.xml mínimo, escrito à mão

POM é Project Object Model, "modelo do projeto". É um arquivo XML: texto com marcações entre < >, em que cada <nome> abre um item e </nome> fecha (parecido com HTML). A Ana criou um projeto novo, caixa, só com este arquivo:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>br.com.ana</groupId>
    <artifactId>caixa</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.release>25</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>
LinhaO que faz
<?xml version="1.0" encoding="UTF-8"?>"Este é um arquivo XML, em UTF-8." Fica sempre na primeira linha.
<project xmlns=… xsi:schemaLocation=…>Abre o projeto. Os endereços dizem "este XML segue o formato de POM 4.0.0"; servem para o editor completar e conferir o arquivo. Copie como está.
<modelVersion>4.0.0</modelVersion>A versão do formato do POM. É sempre 4.0.0 no Maven 3.
<groupId>br.com.ana</groupId>Quem fez: o grupo.
<artifactId>caixa</artifactId>O nome do projeto.
<version>1.0</version>A versão do seu projeto. Junto com o grupo e o nome, forma as coordenadas br.com.ana:caixa:1.0, o "endereço" único do projeto no mundo Maven.
<properties>Configurações em forma de "nome = valor".
<maven.compiler.release>25</…>Compilar para o Java 25 (vira o javac --release 25).
<project.build.sourceEncoding>UTF-8</…>Os .java estão em UTF-8 (para acentos como em "pão" não virarem lixo).
</project>Fecha o projeto.

Só isso. Não há uma linha dizendo onde está o código, como compilar, nem como gerar o JAR: tudo segue a convenção. O 1.0-SNAPSHOT que o arquétipo usou é uma versão "em andamento" (snapshot = "foto do momento"): o -SNAPSHOT avisa que aquela versão ainda muda.

A estrutura de pastas padrão

O código vai em src/main/java, seguindo as pastas do pacote. A Ana criou o caixa da aula de JAR, agora com printf:

$ mkdir -p caixa/src/main/java/br/com/ana/caixa && cd caixa
package br.com.ana.caixa;

public class Caixa {
    public static void main(String[] args) {
        double total = 0;
        for (String a : args) {
            total += Double.parseDouble(a);
        }
        System.out.printf("Itens: %d%n", args.length);
        System.out.printf("Total: R$ %.2f%n", total);
    }
}
PastaO que vai nela
pom.xmlA receita, na raiz do projeto
src/main/java/O código do programa (.java), em pastas por pacote
src/main/resources/Arquivos que não são código e vão junto no JAR (textos, configurações, imagens)
src/test/java/Os testes automatizados (não vão para o JAR)
src/test/resources/Arquivos usados só pelos testes
target/Tudo o que o Maven gera. Nunca edite; pode apagar quando quiser

Missão: esta é a classe Caixa do projeto (sem o package, porque o editor do guia usa um arquivo só). Ela recebe os preços como argumentos. Acrescente uma linha que mostre a média dos preços, no mesmo formato: Média: R$ 5,58.

public class Main {
    public static void main(String[] args) {
        double total = 0;
        for (String a : args) {
            total += Double.parseDouble(a);
        }
        System.out.printf("Itens: %d%n", args.length);
        System.out.printf("Total: R$ %.2f%n", total);
    }
}
public class Main {
    public static void main(String[] args) {
        double total = 0;
        for (String a : args) {
            total += Double.parseDouble(a);
        }
        System.out.printf("Itens: %d%n", args.length);
        System.out.printf("Total: R$ %.2f%n", total);
        System.out.printf("Média: R$ %.2f%n", total / args.length);
    }
}

4. O ciclo de vida: compile, test, package

O Maven organiza o build em fases, numa ordem fixa, como as etapas de uma linha de montagem. Quando você pede uma fase, ele roda todas as anteriores antes:

FaseO que faz
validateConfere se o pom.xml está certo
compileCompila src/main/java para target/classes
testCompila src/test/java e roda os testes
packageCria o JAR em target/
verifyVerificações extras de qualidade (se configuradas)
installCopia o JAR para o seu ~/.m2/repository, para outros projetos seus usarem
deployPublica o JAR num repositório remoto (para a equipe ou o mundo)

Então mvn package = validar + compilar + testar + empacotar. Fora dessa fila existe o mvn clean, que apaga a pasta target.

mvn compile

No projeto loja (o do arquétipo):

$ mvn compile
[INFO] Scanning for projects...
[INFO] Loaded 24119 auto-discovered prefixes for remote repository central (prefixes-central.txt)
[INFO]
[INFO] --------------------------< br.com.ana:loja >---------------------------
[INFO] Building loja 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] Loaded 74 auto-discovered prefixes for remote repository apache.snapshots (prefixes-apache.snapshots.txt)
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ loja ---
[INFO] skip non existing resourceDirectory /home/ana/loja/src/main/resources
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ loja ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  20.224 s
[INFO] Finished at: 2026-10-16T18:24:28-03:00
[INFO] ------------------------------------------------------------------------

(As linhas de download dos plugins de compilação foram omitidas: 64 arquivos, só na primeira vez.)

< br.com.ana:loja >
As coordenadas do projeto (grupo:artefato).
[ jar ]
O tipo de pacote que este projeto gera: um JAR (é o padrão).
--- resources:3.3.1:resources
Plugin resources, versão 3.3.1: copiaria src/main/resources, mas a pasta não existe (skip non existing).
--- compiler:3.13.0:compile
Plugin compiler: chama o javac por você, com --release 25, e põe as classes em target/classes.
Total time: 20.224 s
Lento por causa dos downloads. Da segunda vez, leva poucos segundos.

mvn test

Roda o compile e depois compila e executa os testes, com o plugin Surefire (o "executor de testes" do Maven):

$ mvn test
…                                                    « o começo é igual ao do compile
[INFO] --- compiler:3.13.0:compile (default-compile) @ loja ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ loja ---
[INFO] skip non existing resourceDirectory /home/ana/loja/src/test/resources
[INFO]
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ loja ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 25] to target/test-classes
[INFO]
[INFO] --- surefire:3.3.0:test (default-test) @ loja ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running br.com.ana.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.058 s -- in br.com.ana.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Repare no Nothing to compile - all classes are up to date: o Maven só recompila o que mudou. O resumo Tests run: 1, Failures: 0 diz que o único teste passou. Como escrever testes e ler as falhas fica para Testes com JUnit.

mvn package e a pasta target/

No projeto caixa, o do pom.xml mínimo:

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< br.com.ana:caixa >--------------------------
[INFO] Building caixa 1.0
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] Loaded 24119 auto-discovered prefixes for remote repository central (prefixes-central.txt)
[INFO]
[INFO] --- resources:3.5.0:resources (default-resources) @ caixa ---
[INFO] skip non existing resourceDirectory /home/ana/caixa/src/main/resources
[INFO]
[INFO] --- compiler:3.16.0:compile (default-compile) @ caixa ---
[INFO] Loaded 74 auto-discovered prefixes for remote repository apache.snapshots (prefixes-apache.snapshots.txt)
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
[INFO]
[INFO] --- resources:3.5.0:testResources (default-testResources) @ caixa ---
[INFO] skip non existing resourceDirectory /home/ana/caixa/src/test/resources
[INFO]
[INFO] --- compiler:3.16.0:testCompile (default-testCompile) @ caixa ---
[INFO] No sources to compile
[INFO]
[INFO] --- surefire:3.6.0:test (default-test) @ caixa ---
[INFO] No tests to run.
[INFO]
[INFO] --- jar:3.5.1:jar (default-jar) @ caixa ---
[INFO] Building jar: /home/ana/caixa/target/caixa-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  12.083 s
[INFO] Finished at: 2026-10-16T18:26:09-03:00
[INFO] ------------------------------------------------------------------------
$ ls target
caixa-1.0.jar                « o JAR: artifactId-version.jar
classes                      « os .class
generated-sources
maven-archiver
maven-status
$ java -cp target/caixa-1.0.jar br.com.ana.caixa.Caixa 4.50 10 2.25
Itens: 3
Total: R$ 16,75

Repare que as versões dos plugins são outras (compiler:3.16.0 em vez de 3.13.0). O pom.xml do arquétipo fixa as versões; o mínimo deixa o Maven 3.10.0 escolher as dele. Os dois jeitos funcionam; fixar garante que o build será igual daqui a anos.

No projeto loja, a pasta target depois do mvn package mostra tudo o que o Maven gerou:

$ find target -type f | sort
target/classes/br/com/ana/App.class
target/loja-1.0-SNAPSHOT.jar
target/maven-archiver/pom.properties
target/maven-status/…                                   « 4 arquivos internos do Maven
target/surefire-reports/br.com.ana.AppTest.txt          « relatório dos testes
target/surefire-reports/TEST-br.com.ana.AppTest.xml
target/test-classes/br/com/ana/AppTest.class

JAR executável com o Maven

O JAR do Maven vem sem Main-Class, então dá o erro que você conhece da aula de JAR:

$ java -jar target/caixa-1.0.jar
nenhum atributo de manifesto principal em target/caixa-1.0.jar

Para o Maven escrever o Main-Class, configure o plugin maven-jar-plugin no pom.xml, depois de </properties>:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>br.com.ana.caixa.Caixa</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
<build><plugins><plugin>
"Quero mudar a configuração de um plugin do build."
groupId / artifactId / version
Qual plugin: o que cria o JAR, versão 3.5.1 (a que o Maven já estava usando).
<mainClass>
O nome completo da classe principal; vira o Main-Class do manifesto.
$ mvn package -q                « -q (quiet, "quieto"): só mostra erros
$ java -jar target/caixa-1.0.jar 4.50 10 2.25
Itens: 3
Total: R$ 16,75
$ unzip -p target/caixa-1.0.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.5.1
Java-Version: 25
Build-Jdk-Spec: 25
Main-Class: br.com.ana.caixa.Caixa

mvn clean

$ mvn clean
…
[INFO] --- clean:3.5.0:clean (default-clean) @ caixa ---
[INFO] Deleting /home/ana/caixa/target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
…
$ ls
pom.xml
src

Use mvn clean package (as duas coisas, nessa ordem) quando quiser um build "do zero", por exemplo antes de entregar o JAR ou quando algo estranho acontecer.


5. O repositório local ~/.m2/repository

Tudo o que o Maven baixa fica guardado na pasta .m2/repository dentro da sua pasta pessoal. É uma despensa: o Maven só vai ao "mercado" (o repositório Maven Central, em repo.maven.apache.org) quando falta algo. Por isso o primeiro build demora e os outros são rápidos.

$ du -sh ~/.m2/repository
83M	/home/ana/.m2/repository
$ ls ~/.m2/repository
archetype-catalog-central.xml
archetype-catalog-central.xml.md5
archetype-catalog-central.xml.sha1
com
commons-codec
commons-collections
commons-io
io
javax
org
resolver-status.properties
$ ls ~/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.11.0
junit-jupiter-api-5.11.0.jar             « a biblioteca
junit-jupiter-api-5.11.0.jar.md5         « "impressões digitais" para conferir o download
junit-jupiter-api-5.11.0.jar.sha1
junit-jupiter-api-5.11.0.pom             « o pom.xml da biblioteca (diz de que ELA depende)
junit-jupiter-api-5.11.0.pom.md5
junit-jupiter-api-5.11.0.pom.sha1
_remote.repositories

O caminho segue as coordenadas: org.junit.jupiter vira org/junit/jupiter, depois o artefato e a versão. São 83 MB só para gerar dois projetos pequenos (a maior parte são os próprios plugins do Maven); a pasta cresce com o tempo. Apagá-la é seguro: o Maven baixa de novo o que precisar.


6. Adicionar uma dependência

A Ana quer que o caixa gere um recibo em JSON, o formato de texto que sites e aplicativos usam para trocar dados. Escrever JSON à mão é chato e cheio de detalhes; existe uma biblioteca pequena do Google que faz isso, a Gson. A classe nova:

package br.com.ana.caixa;

import com.google.gson.Gson;
import java.util.List;

public class Recibo {
    record Item(String nome, double preco) {}

    public static void main(String[] args) {
        List<Item> itens = List.of(
                new Item("pão", 4.50),
                new Item("café", 10.0),
                new Item("leite", 2.25));
        Gson gson = new Gson();
        System.out.println(gson.toJson(itens));
    }
}

(O record está explicado em Records e o List.of em ArrayList.) Antes de mexer no pom.xml, veja o que o Maven diz:

Este build falha de propósito
$ mvn compile
…
[INFO] --- compiler:3.16.0:compile (default-compile) @ caixa ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 2 source files with javac [debug release 25] to target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /home/ana/caixa/src/main/java/br/com/ana/caixa/Recibo.java:[3,23] package com.google.gson does not exist
[ERROR] /home/ana/caixa/src/main/java/br/com/ana/caixa/Recibo.java:[14,9] cannot find symbol
  symbol:   class Gson
  location: class br.com.ana.caixa.Recibo
[ERROR] /home/ana/caixa/src/main/java/br/com/ana/caixa/Recibo.java:[14,25] cannot find symbol
  symbol:   class Gson
  location: class br.com.ana.caixa.Recibo
[INFO] 3 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.905 s
[INFO] Finished at: 2026-10-16T18:26:33-03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.16.0:compile (default-compile) on project caixa: Compilation failure: Compilation failure:
[ERROR] /home/ana/caixa/src/main/java/br/com/ana/caixa/Recibo.java:[3,23] package com.google.gson does not exist
…                                                    « os mesmos 3 erros, repetidos
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Como ler um BUILD FAILURE: não comece pelo fim. Procure o primeiro [ERROR]: é a mensagem do javac, a mesma que você já conhece (veja Lendo Erros do javac), com o arquivo e [linha,coluna]: Recibo.java:[3,23] package com.google.gson does not exist. O bloco final repete os erros e dá dicas genéricas (-e, -X, um link); raramente ajuda.

As 5 linhas da dependência

Para dizer ao Maven "este projeto usa a Gson", acrescente um bloco <dependencies> no pom.xml, depois de </properties>:

    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.13.1</version>
        </dependency>
    </dependencies>
<dependencies>
A lista de ingredientes comprados prontos. Cabem quantos <dependency> você quiser.
groupId, artifactId, version
As coordenadas da biblioteca: com.google.code.gson:gson:2.13.1. Você as encontra no site da biblioteca ou pesquisando em central.sonatype.com (a busca do Maven Central), que mostra o bloco pronto para copiar.
(sem <scope>)
Usada pelo programa. Bibliotecas usadas só nos testes, como o JUnit, levam <scope>test</scope>.
$ mvn compile
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< br.com.ana:caixa >--------------------------
[INFO] Building caixa 1.0
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] Loaded 24119 auto-discovered prefixes for remote repository central (prefixes-central.txt)
Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.pom
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.pom (13 kB at 27 kB/s)
…                                                    « mais 3 arquivos .pom, entre eles o da error_prone_annotations
Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar (287 kB at 1.7 MB/s)
Downloading from central: https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0.jar
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0.jar (20 kB at 291 kB/s)
[INFO]
[INFO] --- resources:3.5.0:resources (default-resources) @ caixa ---
[INFO] skip non existing resourceDirectory /home/ana/caixa/src/main/resources
[INFO]
[INFO] --- compiler:3.16.0:compile (default-compile) @ caixa ---
[INFO] Loaded 74 auto-discovered prefixes for remote repository apache.snapshots (prefixes-apache.snapshots.txt)
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 2 source files with javac [debug release 25] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Leia os downloads: o Maven baixou o gson-2.13.1.pom, descobriu nele que a Gson precisa de outra biblioteca, a error_prone_annotations, e baixou essa também. Isso se chama dependência transitiva ("a dependência da sua dependência"). Num projeto real, 5 dependências escritas no pom.xml podem virar 50 JARs; o Maven cuida de todos.

A biblioteca agora está na despensa, e o javac do Maven a usou no classpath. Para rodar o Recibo fora do Maven, o classpath precisa da Gson também (sem ela, o erro é o mesmo da aula de JAR):

$ java -cp target/classes br.com.ana.caixa.Recibo
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/Gson
	at br.com.ana.caixa.Recibo.main(Recibo.java:14)
Caused by: java.lang.ClassNotFoundException: com.google.gson.Gson
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
	... 1 more
$ java -cp target/classes:$HOME/.m2/repository/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar br.com.ana.caixa.Recibo
[{"nome":"pão","preco":4.5},{"nome":"café","preco":10.0},{"nome":"leite","preco":2.25}]

Esse -cp gigante mostra o problema que o Maven resolve. Na prática, para rodar com todas as dependências, usa-se um plugin (como o exec-maven-plugin, com mvn exec:java) ou um que gera um JAR "gordo" com as bibliotecas dentro (maven-shade-plugin); o Gradle já traz isso pronto com gradle run.

Missão: sinta o que a biblioteca economiza. Sem a Gson, monte você mesmo o JSON do recibo, idêntico ao que ela gerou: [{"nome":"pão","preco":4.5},{"nome":"café","preco":10.0},{"nome":"leite","preco":2.25}]. Falta pôr a vírgula entre os itens (não antes do primeiro).

public class Main {
    public static void main(String[] args) {
        String[] nomes = {"pão", "café", "leite"};
        double[] precos = {4.5, 10.0, 2.25};
        StringBuilder json = new StringBuilder("[");
        for (int i = 0; i < nomes.length; i++) {
            json.append("{\"nome\":\"").append(nomes[i])
                .append("\",\"preco\":").append(precos[i]).append("}");
        }
        json.append("]");
        System.out.println(json);
    }
}
public class Main {
    public static void main(String[] args) {
        String[] nomes = {"pão", "café", "leite"};
        double[] precos = {4.5, 10.0, 2.25};
        StringBuilder json = new StringBuilder("[");
        for (int i = 0; i < nomes.length; i++) {
            if (i > 0) {
                json.append(",");
            }
            json.append("{\"nome\":\"").append(nomes[i])
                .append("\",\"preco\":").append(precos[i]).append("}");
        }
        json.append("]");
        System.out.println(json);
    }
}

7. Formas diferentes de criar um projeto Maven

FormaVantagemDesvantagem
mvn archetype:generate … -DinteractiveMode=falseUm comando; já vem com JUnit 5 e versões de plugins fixadaspom.xml longo, com coisas que você ainda não entende
mvn archetype:generate (sem opções)Pergunta tudo, passo a passoMostra uma lista enorme de moldes; fácil se perder
pom.xml escrito à mãoVocê entende cada linhaPrecisa criar as pastas e lembrar do formato
Pela IDE (IntelliJ, VS Code, Eclipse)Formulário com botões; a IDE roda o Maven por vocêEsconde o que acontece (veja Editores e IDEs)

Para estudar, comece pelo pom.xml mínimo e acrescente só o que precisar. Em qualquer caso, o projeto final é igual: um pom.xml e a pasta src.


Quando dá errado

Dependência que não existe

A Ana digitou a versão errada (2.99.0, que não existe):

$ mvn compile
…
Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.99.0/gson-2.99.0.pom
[WARNING] The POM for com.google.code.gson:gson:jar:2.99.0 is missing, no dependency information available
Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.99.0/gson-2.99.0.jar
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.967 s
[INFO] Finished at: 2026-10-16T18:26:43-03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project caixa: Could not resolve dependencies for project br.com.ana:caixa:jar:1.0
[ERROR] dependency: com.google.code.gson:gson:jar:2.99.0 (compile)
[ERROR] 	Could not find artifact com.google.code.gson:gson:jar:2.99.0 in central (https://repo.maven.apache.org/maven2)
[ERROR] -> [Help 1]
…

O que aconteceu: Could not resolve dependencies = "não consegui obter as dependências". Could not find artifact … in central: o Maven procurou as coordenadas no Maven Central e não achou. Causas: versão, groupId ou artifactId digitados errado, ou sem internet (aí a mensagem fala em conexão).

Rodando de novo, a mensagem muda:

[ERROR] 	com.google.code.gson:gson:jar:2.99.0 was not found in https://repo.maven.apache.org/maven2 during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of central has elapsed or updates are forced

O Maven anotou a falha na despensa e não tenta de novo por um tempo. Como resolver: corrija as coordenadas (copie de central.sonatype.com). Se a versão era certa e o problema foi a internet, force uma nova tentativa com mvn -U compile (-U = update).

there is no POM in this directory
$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.095 s
[INFO] Finished at: 2026-10-16T18:27:24-03:00
[INFO] ------------------------------------------------------------------------
[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/home/ana). Please verify you invoked Maven from the correct directory. -> [Help 1]
…

O que aconteceu: você rodou o Maven fora da pasta do projeto (aqui, em /home/ana). Como resolver: cd para a pasta onde está o pom.xml.

COMPILATION ERROR / BUILD FAILURE

O que aconteceu: o javac recusou o código. A mensagem é a do javac, no formato Arquivo.java:[linha,coluna] mensagem. Como resolver: leia o primeiro [ERROR], corrija o código como faria sem o Maven. Se for package … does not exist de uma biblioteca, falta a <dependency>.

Aviso: 'build.plugins.plugin.version' … is missing

Quando a Ana configurou o maven-jar-plugin pela primeira vez, esqueceu a linha <version>:

$ mvn clean
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for br.com.ana:caixa:jar:1.0
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-jar-plugin is missing. @ line 27, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
…

O que quer dizer: é só um aviso (o build continuou), mas sério: sem versão, o plugin pode mudar sozinho quando o Maven for atualizado. Como resolver: ponha <version> em todo plugin que aparecer em <build>.

release version 26 not supported

O projeto pede um Java mais novo do que o JDK que o Maven está usando. A Ana testou trocando o 25 por 26 no pom.xml (o laboratório tem o JDK 25):

$ mvn compile
…
[INFO] Compiling 2 source files with javac [debug release 26] to target/classes
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.996 s
[INFO] Finished at: 2026-10-16T18:30:53-03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.16.0:compile (default-compile) on project caixa: Fatal error compiling: error: release version 26 not supported -> [Help 1]
…

O que aconteceu: o javac do JDK 25 não sabe gerar código para o Java 26. O mesmo acontece com um projeto para Java 25 num computador com JDK 21 (release version 25 not supported). Como confirmar: mvn -version, linha Java version. Como resolver: use no pom.xml uma versão igual ou menor que a do seu JDK, ou aponte a variável JAVA_HOME para um JDK mais novo (veja Instalar no Linux).


Referência

ComandoO que faz
mvn -versionVersão do Maven e do Java que ele usa
mvn archetype:generate -DgroupId=… -DartifactId=… -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=falseCria um projeto a partir de um molde
mvn compileCompila src/main/java → target/classes
mvn testCompila e roda os testes
mvn packageCompila, testa e cria o JAR em target/
mvn cleanApaga target/
mvn clean packageBuild do zero
mvn installPackage + copia o JAR para ~/.m2/repository
mvn -q …Saída silenciosa (só erros)
mvn -U …Força procurar de novo dependências que falharam
mvn -e … / mvn -X …Mais detalhes do erro / modo depuração (muito texto)

Exercícios

1. Onde vai o código?

A classe br.com.ana.agenda.Contato num projeto Maven fica no arquivo:

2. Gerar o JAR

Complete o comando que apaga o target e gera o JAR do zero:

mvn

3. Java 25 no pom

Complete a propriedade que manda compilar para o Java 25:

<>25</…>

4. Você roda mvn package. Quais fases o Maven executa?

5. Num BUILD FAILURE longo, onde está a informação mais útil?

6. Você pôs a Gson no pom.xml, e o Maven baixou também a error_prone_annotations. Por quê?


Resumo

  • O Maven baixa as dependências (e as dependências delas) e faz o build do mesmo jeito em qualquer projeto.
  • O pom.xml descreve o projeto: coordenadas groupId:artifactId:version, propriedades (como maven.compiler.release), dependências e plugins.
  • Convenção: código em src/main/java, testes em src/test/java, tudo o que é gerado em target/.
  • Fases: compile → test → package → install; pedir uma roda as anteriores. clean apaga o target.
  • Downloads ficam em ~/.m2/repository: o primeiro build é lento, os outros não.
  • Para ler um BUILD FAILURE, procure o primeiro [ERROR].
  • Could not resolve dependencies = coordenadas erradas ou sem internet; depois de corrigir, -U força nova tentativa.