Construcción de aplicaciones Java con Maven

Maven es la herramienta por excelencia para controlar la construcción y descargar dependencias de cualquier aplicación Java. Desde la compilación hasta la construcción del binario final pasando por los test unitarios. En las siguientes líneas te enseñamos lo que debes saber para convertirte en un profesional de Maven.

Qué es Maven

Maven es una herramienta Open Source desarrollada en Java por la asociación Apache Foundation, un organismo sin ánimo de lucro que publica recursos libres de derechos para asegurar el desarrollo y la innovación en las tecnologías de la información. El objetivo de esta herramienta es facilitar y estandarizar la organización y la construcción de proyectos de software, principalmente para proyectos destinados a la máquina virtual de Java.

Cómo instalar Maven

Puedes consultar el artículo de instalación de maven para obtener un proceso detallado de cómo proceder para dejarlo bien configurado en tu estación de desarrollo.

Organización de archivos

Ejemplo de proyecto con Maven

Maven define que todo proyecto Java, ya sea para construir una librería o para una aplicación, debe tener la siguiente estructura de directorios en el sistema de ficheros:

Prácticamente todos los editores de programación de Java trabajan perfectamente con los proyectos organizados como indica Maven. Se puede considerar que se ha convertido en un estándar de facto. Los editores automáticamente procesan el fichero pom.xml para tener presente las dependencias necesarias y ajustar la configuración del proyecto acorde con lo especificado en el fichero.

Fases de construcción

Una vez definido cómo deben organizarse los ficheros fuente que constituyen un proyecto, el siguiente paso es invocar a Maven para que pueda realizar el proceso de construcción del proyecto. Maven tiene presente las dependencias entre módulos que puede haber, así que si se trata de un proyecto modular, el orden de construcción de los módulos se realizará en el orden correcto que permita satisfacer las dependencias. La construcción de cada módulo individual se realiza de la misma manera que se hace sobre un proyecto simple. Por tanto, ya sea para un módulo o para un proyecto simple, Maven tratará de construir el módulo o proyecto, pasando siempre por las siguientes fases en el orden que se indica:

  1. validate: valida que el proyecto es correcto y que toda la información necesaria está disponible según la especificación de los POMs.
  2. compile: compila el código fuente del proyecto revisando todos los directorios src/main/java, alojando los ficheros .class en target/classes.
  3. test: prueba el código fuente compilado utilizando el marco de prueba unitario indicado en el POM, normalmente JUnit. En esta fase se lanza la ejecución de todos los test. Si el resultado de alguno de ellos no es correcto se interrumpe la construcción.
  4. package: recoge el código compilado y lo empaqueta en su formato distribuible, normalmente como un fichero del tipo <application>.jar.
  5. verify: ejecuta cualquier comprobación de los resultados de las pruebas de integración para garantizar que se cumplan los criterios de calidad.
  6. install: instala el paquete en el repositorio local, para usarlo como dependencia en otros proyectos locales.
  7. deploy: copia el binario construido en el repositorio remoto, para compartirlo con otros desarrolladores y proyectos. Esta fase requiere que se indique la URL del repositorio donde desplegar, así como también las credenciales a usar en caso necesario.
  8. clean: (opcional) Si se invoca manualmente, Maven eliminará todos los recursos generados durante la compilación y el empaquetado, borrando el directorio target.
  9. site: (opcional) produce un informe en HTML acerca del proyecto mostrando la documentación del API de Javadoc y estadísticas según las herramientas de análisis que se hayan configurado.

En la mayoría de las veces será suficiente con lanzar la ejecución de Maven parando en algún momento anterior al deploy si se trabaja localmente. Por ejemplo, en muchas ocasiones bastará con ejecutar package si es una aplicación simple o install si se trata de la actualización de algún módulo usado por otra aplicación. Para indicar hasta qué punto se desea ejecutar la construcción de un proyecto, en la línea de comandos ubicándose el directorio donde está alojado el pom.xml, se invocará a Maven mediante el comando mvn argumentando la fase donde finalizar:

# update target/classes
mvn compile

# install binary into local repository
mvn install

# both steps
mvn compile install

# clean resources before install
mvn clean install

Sea cual sea la fase indicada, si pasa por package, Maven dejará disponible el binario localmente ubicado en el directorio target del proyecto o módulo correspondiente.

Gestión de dependencias

Uno de los mayores beneficios del uso de Maven es la buena gestión de dependencias que realiza la herramienta juntamente con el gran catálogo de librerías que ofrece públicamente. Todas ellas sin ningún coste de uso. Maven viene configurado de serie con unos repositorios públicos donde se despliegan la mayoría de librerías Open Source del ecosistema de Java. Para hacer uso de cualquiera, bastará con indicar una nueva dependencia en el POM del proyecto.

Cuando el proyecto requiere de una dependencia, Maven irá a buscarlo al repositorio local. Si la librería no está alojada ahí, normalmente un fichero con extensión .jar, tratará de descargarlo de Internet buscando en los repositorios públicos. Si lo encuentra remotamente, guardará una copia local para que esté disponible para la siguiente vez. El directorio por defecto del repositorio local suele estar en <home_usuario>/.m2/repository. Aunque puede indicarse una ruta alternativa en el fichero de configuración de Maven <home_usuario>/.m2/settings.xml. Mientras no se indique lo contrario, todas las dependencias de todos los proyectos serán almacenadas en ese directorio. Así que fácilmente pueden acumularse varios Gigas de información a medida que avanza el uso de diferentes librerías y versiones en el conjunto de los proyectos. El usuario es libre de eliminar el contenido de éste, provocando que Maven deba descargar de nuevo las dependencias necesarias.

Las dependencias del proyecto deben ir dentro de la sección de <dependencies>. Debe tenerse en cuenta que éstas pueden tener diferentes ámbitos de uso denominados scopes. El ámbito se indica en el atributo <scope> del XML y permite separar aquellas dependencias que son necesarias para compilar, de otras que serán sólo requeridas durante la ejecución del aplicativo. Maven soporta los siguientes scopes:

En la mayoría de las ocasiones sólo será necesario indicar el ámbito de tipo test, puesto que el otro ámbito compile será aplicado por Maven automáticamente en ausencia del dato. Independientemente del ámbito, todas las dependencias deben ir dentro de la sección <dependencies>:

<project ...>
    ...
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        ...
    </dependencies>
    ...
</project>

La gran variedad de dependencias existentes en Maven hace difícil que el programador pueda recordar qué datos indicar a la hora de incluir una librería. Además, Java está compuesta por una comunidad muy activa de programadores que liberan nuevos recursos y actualizaciones con frecuencia. Todo ello complica la tarea de añadir una librería o artefacto dentro del proyecto. Para facilitar esta tarea existe un página web que ofrece una interfaz de usuario destinada al programador. En ella el usuario puede localizar y copiar la dependencia cómodamente en el POM del proyecto. Esta página hace uso de los mismos repositorios públicos que usa Maven indexando todo su contenido:

La página web ofrece estadísticas de uso de las principales librerías que pueden ser útiles para descubrir otros proyectos a tener presente en futuros desarrollos. A medida que los proyectos crecen, la lista de dependencias también lo hace y por regla de tres, las dependencias transitivas de las librerías incluidas. En ocasiones puede ocurrir que dos dependencias entren en conflicto al usar internamente versiones diferentes de una misma librería. Encontrar y resolver esta situación requiere un trabajo de investigación y de búsquedas por la red no trivial. Una opción que ayuda al diagnóstico es mediante Maven. Se le puede solicitar que muestre información de cómo ha resuelto las dependencias directas e indirectas, indicando qué versión de cada una de ellas se está aplicando.

Para ver el resultado de la resolución de los requerimientos debe ejecutarse el siguiente comando:

mvn dependency:tree

Esta sentencia imprimirá por consola la resolución de dependencias usadas durante la compilación y el empaquetado de la aplicación. Resulta muy útil a la hora de solucionar alguna incompatibilidad entre librerías usadas o comportamientos anómalos en tiempo de ejecución.

Primera aplicación con Maven

La manera más sencilla de realizar una primera aplicación con Maven y Java es invocar al asistente de Maven para que cree un esqueleto de aplicación. Para ello necesitamos hacerle llegar el grupo, y el nombre del proyect (artifactId) al asistente que puede invocarse desde el terminal.

Por ejemplo si queremos crear un proyecto con el grupo: org.eadp y artifact:my-app ejecutaremos el siguiente comando:

mvn archetype:generate \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DinteractiveMode=false \
    -DgroupId=org.eadp \
    -DartifactId=my-app
    

La ejecución de un arquetipo de Maven no es más que la aplicación de una plantilla predeterminada que genera un esqueleto de aplicación, creando el contenido dentro del directorio con el mismo nombre que el dado al proyecto a través de la variable artifactId.

Ejemplo de proyecto creado con el arquetipo de Maven

El proyeto puede ser importado sin ningún problema desde cualquier editor de programación de Java con soporte para Maven. Pruebe de realizar la construcción del proyecto con mvn package para ver qué sucede.

El generador crea un test inicial como plantilla para que el programador tenga una referencia rápida de cómo crear los tests y poder así aplicar una metodología de desarrollo basada en tests. Puede lanzar la ejecución de los tests desde el terminal de comandos con mvn test

En cualquier caso, le recomendamos que se familiarice con el uso de su IDE de Java preferido que simplificará enormemente las tareas de construcción, depuración, tests y cualquier otra tarea diaria del programador.

Déjanos tus comentarios abajo o escríbenos para compartir tu experiencia o para mejorar este contenido. Saludos!