Notas Avançadas sobre Configuração e Uso do Maven

Boas Práticas para o Arquivo settings.xml

O arquivo de configuração do Maven está localizado em M2_HOME/conf/settings.xml. Modificar diretamente esse arquivo afeta globalmente todos os usuários do sistema operacional. A abordagem recomendada é copiar esse arquivo para ~/.m2/settings.xml, criando uma configuração isolada por usuário, sem interferir entre diferentes contas no mesmo máquina.

Essa estratégia também simplifica atualizações do Maven: ao instalar uma nova versão, não é necessário reconfigurar o arquivo, pois as definições personalizadas permanecem no diretório do usuário.

Verificando a Instalação

Após descompactar o Maven, configurar variáveis de ambiente e ajustar o settings.xml, execute:

mvn help:system

Esse comando utiliza o plugin help para exibir informações do sistema. Caso o plugin não esteja disponível localmente, o Maven fará o download a partir do repositório remoto, validando assim a conectividade e as configurações de repositório. O comando mvn -v apenas confirma a instalação e as variáveis de ambiente, sem validar alterações no settings.xml.

Definindo a Versão do Compilador Java

Por padrão, o Maven pode utilizar uma versão antiga do compilador. É recomendável especificar explicitamente a versão desejada:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
    </plugins>
</build>

Criando Projetos com Archetype

Para gerar a estrutura inicial de um projeto via linha de comando:

mvn archetype:generate

O Maven solicitará a seleção de um arquétipo e, em seguida, os parâmetros groupId, artifactId, version e package.

Gerando um JAR Executável

O JAR produzido pelo ciclo padrão de build não é executável diretamente, pois o manifesto não contém a classe principal. Para resolver isso, utiliza-se o maven-shade-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.exemplo.AppPrincipal</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

O JAR resultante poderá ser executado com java -jar arquivo.jar.

Gerenciamento de Dependências

Excluindo Dependências Transitivas

Conflitos de versão podem surgir devido à dependência transitiva. Para excluir uma biblioteca indesejada que vem arrastada por outra:

<dependency>
    <groupId>com.exemplo</groupId>
    <artifactId>modulo-principal</artifactId>
    <version>2.1.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.exemplo</groupId>
            <artifactId>modulo-indesejado</artifactId>
        </exclusion>
    </exclusions>
</dependency>

A tag <exclusions> pode conter múltiplos elementos <exclusion>, sendo necessário apenas groupId e artifactId para identificar unicamente a dependência.

Dependências Opcionais

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.18</version>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

O atributo optional indica que essa dependência está disponível apenas para o projeto atual. Projetos downstream que dependam deste não receberão essa biblioteca por transitividade, devendo declará-la explicitamente caso necessário.

Repositórios

Configurando Repositórios Remotos

O repositório local padrão fica em ~/.m2/repository. Para alterar o caminho, modifique o elemento localRepository no settings.xml. Já os repositórios remotos são configurados no POM do projeto:

<repositories>
    <repository>
        <id>jboss-repo</id>
        <name>Repositório JBoss</name>
        <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        <releases>
            <enabled>true</enabled>
            <updatePolicy>daily</updatePolicy>
            <checksumPolicy>ignore</checksumPolicy>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <layout>default</layout>
    </repository>
</repositories>

updatePolicy controla a frequência de verificação de atualizações: daily (padrão), never, always ou interval:X (a cada X minutos). checksumPolicy define o comportamento ao falhar a verificação de checksum: warn (padrão), fail ou ignore.

Autenticação em Repositórios Remotos

As credenciais de acesso não devem ser armazenadas no POM, pois este é versionado em controle de código. Elas devem ser declaradas no settings.xml:

<servers>
    <server>
        <id>jboss-repo</id>
        <username>usuario</username>
        <password>senha</password>
    </server>
</servers>

O id deve coincidir com o id do repositório definido no POM, estabelecendo a ligação entre a configuração de repositório e as credenciais.

Herança e Agregação

Agregação reúne múltiplos módulos em um projeto unificado, enquanto herança permite que módulos filhos reaproveitem configurações do pai. Na prática, o POM pai centraliza ambas as funções:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.exemplo</groupId>
    <artifactId>projeto-pai</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0-SNAPSHOT</version>
    
    <properties>
        <java.version>11</java.version>
    </properties>
    
    <modules>
        <module>modulo-core</module>
        <module>modulo-web</module>
    </modules>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>5.3.0</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

dependencyManagement e pluginManagement apenas declararam versões sem importar de fato as dependências. Os módulos filhos precisam declarar explicitamente as dependências desejadas, herdando apenas a versão gerenciada pelo pai.

Para importar configurações de gerenciamento de um POM externo, utilize o escopo import:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.exemplo</groupId>
            <artifactId>bom-configuracoes</artifactId>
            <version>2.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

No módulo filho, a herança é estabelecida com a tag <parent>:

<parent>
    <groupId>com.exemplo</groupId>
    <artifactId>projeto-pai</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</parent>

Build Seletivo de Módulos

Em projetos grandes, construir todos os módulos é dispendioso. O Maven oferece parâmetros para construir apenas o necessário, respeitando a ordem de dependências (conceito de reator):

  • -am (also-make): constrói o módulo especificado e suas dependências
  • -amd (also-make-dependents): constrói módulos que dependem do módulo especificado
  • -pl (projects): lista de módulos separados por vírgula
  • -rf (resume-from): retoma o build a partir de um módulo específico

Exemplo: compilar o módulo modulo-web e suas dependências:

mvn clean install -pl modulo-web -am

Super POM

Todos os POMs herdam de um Super POM, que define configurações padrão como estrutura de diretórios (src/main/java, src/test/java), diretório de saída (target) e versões de plugins essenciais. Esse arquivo está dentro de $M2_HOME/lib/maven-model-builder-*.jar em org/apache/maven/model/pom-4.0.0.xml.

Para sobrescrever convenções (não recomendado), modifique o elemento <build>:

<build>
    <sourceDirectory>src/codigo</sourceDirectory>
</build>

Testes

Ignorando Testes

Durante o desenvolvimento, pode ser necessário pular testes. Há duas abordagens:

1. Via linha de comando (temporário):

mvn package -DskipTests

Compila os testes, mas não os executa. Para pular também a compilação:

mvn package -Dmaven.test.skip=true

2. Via configuração de plugin (persistente):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <skipTests>true</skipTests>
    </configuration>
</plugin>

Para pular também a compilação dos testes, adicione:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <executions>
        <execution>
            <id>testCompile</id>
            <phase>none</phase>
        </execution>
    </executions>
</plugin>

Executando Testes Específicos

O parâmetro test permite selecionar testes:

mvn test -Dtest=ClasseDeTeste

Curingas são aceitos: -Dtest=*Integracao*. Para múltiplas classes, use vírgulas. Se nenhum teste corresponder, use -DfailIfNoTests=false para evitar erro:

mvn test -Dtest=*Integracao* -DfailIfNoTests=false

Incluindo e Excluindo Testes

Por padrão, classes terminadas em Test são reconhecidas. Para incluir classes com sufixo Tests:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <includes>
            <include>**/*Tests.java</include>
        </includes>
    </configuration>
</plugin>

Para excluir testes específicos:

<configuration>
    <excludes>
        <exclude>**/*TesteTemporario.java</exclude>
    </excludes>
</configuration>

Empacotando Testes em JAR

Para disponibilizar classes de teste como dependência em outros projetos:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.2.0</version>
    <executions>
        <execution>
            <goals>
                <goal>test-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

O artefato gerado (artifactId-tests.jar) pode ser declarado como dependência:

<dependency>
    <groupId>com.exemplo</groupId>
    <artifactId>modulo-core</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>

Plugins de Servidor Web

Jetty

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.44.v20210927</version>
    <configuration>
        <scanIntervalSeconds>10</scanIntervalSeconds>
        <webApp>
            <contextPath>/app</contextPath>
        </webApp>
    </configuration>
</plugin>

scanIntervalSeconds define o intervalo de escaneamento de alterações para hot reload. contextPath define o caminho da aplicação (http://localhost:8080/app/).

Para simplificar a execução, adicione o groupId do plugin no settings.xml:

<settings>
    <pluginGroups>
        <pluginGroup>org.eclipse.jetty</pluginGroup>
    </pluginGroups>
</settings>

Comandos de execução:

mvn jetty:run
mvn jetty:run -Djetty.port=9090

Tomcat

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <port>8080</port>
    </configuration>
</plugin>

Execução:

mvn tomcat7:run

Como o plugin não recebe atualizações há bastante tempo, recomenda-se deploy diretamente no contêiner Tomcat.

Propriedades do Maven

O Maven possui seis categorias de propriedades que funcionam como variáveis:

  • Internas: ${basedir} (diretório raiz do projeto) e ${version} (versão do projeto)
  • POM: referenciam elementos do POM, como ${project.groupId}, ${project.artifactId}, ${project.build.sourceDirectory}, ${project.build.finalName}
  • Customizadas: definidas em <properties>: ``` <versao.spring>5.3.0</versao.spring>
    
     Usadas como `${versao.spring}`
    
  • Settings: referenciam settings.xml, como ${settings.localRepository}
  • Sistema Java: propriedades da JVM, como ${user.home}. Liste todas com mvn help:system
  • Variáveis de ambiente: prefixadas com env., como ${env.JAVA_HOME}

Em projetos multi-módulo, essas propriedades reduzem redundância:

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>modulo-dao</artifactId>
    <version>${project.version}</version>
</dependency>

Tags: maven build-automation POM dependency-management Maven-plugins

Publicado em 7-26 02:31