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.
- O que é o Maven e quais problemas ele resolve (dependências e build padronizado).
- Criar um projeto com
mvn archetype:generatee, também, escrevendo opom.xmlà mão. - O
pom.xmlmí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 cleane a pastatarget/.- O repositório local
~/.m2/repositorye 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:
| Problema | Sem Maven | Com 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ão | Escrever 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 jeito | mvn 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=valorpassa 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>
| Linha | O 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);
}
}
| Pasta | O que vai nela |
|---|---|
pom.xml | A 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:
| Fase | O que faz |
|---|---|
validate | Confere se o pom.xml está certo |
compile | Compila src/main/java para target/classes |
test | Compila src/test/java e roda os testes |
package | Cria o JAR em target/ |
verify | Verificações extras de qualidade (se configuradas) |
install | Copia o JAR para o seu ~/.m2/repository, para outros projetos seus usarem |
deploy | Publica 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: copiariasrc/main/resources, mas a pasta não existe (skip non existing). - --- compiler:3.13.0:compile
- Plugin
compiler: chama ojavacpor você, com--release 25, e põe as classes emtarget/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-Classdo 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:
$ 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 emcentral.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
| Forma | Vantagem | Desvantagem |
|---|---|---|
mvn archetype:generate … -DinteractiveMode=false | Um comando; já vem com JUnit 5 e versões de plugins fixadas | pom.xml longo, com coisas que você ainda não entende |
mvn archetype:generate (sem opções) | Pergunta tudo, passo a passo | Mostra uma lista enorme de moldes; fácil se perder |
pom.xml escrito à mão | Você entende cada linha | Precisa 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
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>.
'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
| Comando | O que faz |
|---|---|
mvn -version | Versão do Maven e do Java que ele usa |
mvn archetype:generate -DgroupId=… -DartifactId=… -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false | Cria um projeto a partir de um molde |
mvn compile | Compila src/main/java → target/classes |
mvn test | Compila e roda os testes |
mvn package | Compila, testa e cria o JAR em target/ |
mvn clean | Apaga target/ |
mvn clean package | Build do zero |
mvn install | Package + 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:
3. Java 25 no pom
Complete a propriedade que manda compilar para o Java 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.xmldescreve o projeto: coordenadasgroupId:artifactId:version, propriedades (comomaven.compiler.release), dependências e plugins. - Convenção: código em
src/main/java, testes emsrc/test/java, tudo o que é gerado emtarget/. - Fases:
compile→test→package→install; pedir uma roda as anteriores.cleanapaga otarget. - 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,-Uforça nova tentativa.