4. Maven#

Maven es un gestor de proyectos escritos en Java, esto es, una herramienta que automatiza la construcción y la gestión de aplicaciones escritas en Java, lo cual implica simplificar las tareas de creación, gestión de dependencias, compilación, pruebas, empaquetado y despliegue de la aplicación.

Para ello provee de una orden (mvn) provista de subórdenes que modularizan las distintas tareas de las que se encarga.

Nota

Visual Studio Code tiene una extensión que nos abstrae de todos estos comandos, por lo que este apéndice no tiene más interés qué tener una idea de qué es lo que subyace por debajo.

4.1. Creación#

Se impone una estructura estandarizada para el proyecto que podemos resumir en el siguiente gráfico:

+-- src
|    +-- main/
|    |     +-- java/edu/acceso/miapp/  (Código de la aplicación)
|    |     +-- resources/              Archivos de configuración, etc.
|    |
|    +-- test/                         Reproduce la estruct. de main para pruebas
|
+-- target/                            Código generado
+-- pom.xml                            Configuración del proyecto.

El subcomando asociado a esta fase es archetype:generate:

$ mvn archetype:generate -DgroupId=edu.acceso.test \
    -DartifactId=miapp
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -Dversion=1.0.0 \
    -DinteractiveMode=false

Pero lo habitual es que el IDE nos abstraiga de esta fase y se encargue el mismo de ejecutar la orden cuando le pidamos iniciar el proyecto.

4.2. Dependencias#

También facilita el gestor la tarea de obtener las dependencias de nuestro proyecto descargándolas directamente del Repositorio General de Maven. Basta incluirla en pom.xml. Por ejemplo:

<dependencies>
   <dependency>
       <groupId>jakarta.persistence</groupId>
       <artifactId>jakarta.persistence-api</artifactId>
       <version>3.2.0</version>
   </dependency>

   <!-- Otras dependencias -->
</dependencies>

La página tiene un buscador y puede buscarse a través de él la librería. La del ejemplo se haya en la dirección persistence-api, y escogiendo la versión deseada, se obtiene el código exacto que debe añadirse al archivo. Las librerías, además, pueden a su vez contener dependencias, pero se calculan si necesidad de incluirlas explícitamente.

La suborden asociada a la obtención de dependencias es:

$ mvn dependency:resolve
$ mvn dependency:tree         # Muestra el árbol de dependencias.

Sin embargo, no es necesario efectuar esta operación explícitamente, porque se realiza automáticamente al realizar operaciones posteriores.

4.3. Compilación#

La compilación, esto es, la generación de bytecode se realiza a través del plugin maven-compiler-plugin. Hacer la operación, en principio, es sencillo:

$ mvn compile                  # Genera el bytecode.
$ mvn clean compile            # Genera borrando antes el código generado previo

Ahora bien, hay distintas versiones de Java y, al respecto, el compilador (javac) necesita que se le indiquen dos cosas:

  1. Para qué versión de Java se realiza la comprobación estática de código.

  2. Para qué versión de Java se genera el bytecode[1].

En ausencia de configuración al respecto, el plugin le indica al compilador que use para ambas cosas la antigua version 1.7[2], por lo que es muy recomendable indicar explícitamente en el archivo pom.xml una versión algo más moderna, e indispensable si se van a usar características del lenguaje más modernas. Puede hacerse como una propiedad:

<properties>
   <maven.compiler.release>21</maven.compiler.release>
</properties>

o directamente configurando explíciamente el plugin (que en principio no necesita ser declarado):

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

Consejo

Configurarlo como propiedad permite usar el valor declarado de la versión en otras partes del archivo, que necesiten indicar también la versión. Por ejemplo, al configurar el plugin para generar la documentación con Javadoc.

Nota

La opción --release que engloba ambos aspectos de la compilación apareció en Java 9. Antes no existía y se usaban en su lugar --source y --target (que, no obstante, siguen existiendo), por lo que si se quiere mantener compatibilidad con un JDK antiguo podemos hacer:

<properties>
   <maven.compiler.source>21</maven.compiler.source>
   <maven.compiler.target>21</maven.compiler.target>
</properties>

o la configuración correspondiente directamente en el plugin.

4.4. Pruebas#

El código que prueba la aplicación debe escribirse bajo src/test/ con la misma estructura que se uso en src/main/.

Las subórdenes asociadas a esta fases son:

$ mvn test              # Compila todo el código (principal y pruebas) y ejecuta las pruebas
$ mvn test-compile      # Sólo compila las pruebas sin llegar a ejecutarlas.

4.5. Empaquetado#

El software compilado suele distribuirse en formato JAR, un archivo zip que contiene las clases compiladas (archivos .class) y algunos otros archivos adicionales. Para crearlo:

$ mvn clean package

Para la generación del paquete, Maven usa el plugin maven-jar-plugin, que no incluye dependencias. Para más información sobre ello y cómo incluirlas consulte este gist sobre generación de paquetes.

Notas al pie