Maven: Crear un jar de una aplicación Java con sus dependencias

mavenLogo

Recientemente he estado trabajando en un proyecto Java en el cual he tenido que usar bastantes dependencias (librerías externas) y algunas de ellas tenían a su vez dependencias transitivas. En esta ocasión os contaré mi experiencia con el proyecto y haré una pequeña guía para lo que más me ha costado, que ha sido empaquetar todo el proyecto en un único jar ejecutable.

Introducción a Maven

Inicié el proyecto como un proyecto de Java normal y corriente, cuando empecé a necesitar las librerías las iba añadiendo, pero pronto me dí cuenta del problema de las dependencias transitivas de las librerías que estaba usando y me volví loco para ver cuales eran e ir añadiéndolas al classpath del proyecto.

Me dí cuenta de que aquello era insostenible, había que cambiar, sabía de la existencia de Maven, pero nunca lo había usado y por falta de tiempo me resistía al cambio. Pero no había duda, el cambio era necesario.

Para aquellos que no lo sepan Maven es una herramienta de construcción automática de proyectos tal como lo puede ser ant (del que ya hicimos una guía hace tiempo), pero con una gran ventaja, el manejo automático de las dependencias. No es necesaria la descarga de las librerías, lo único que hay que hacer es especificarlas en el fichero pom.xml de configuración y maven se encargará de descargar las dependencias al repositorio local; y como no, también descargará las dependencias transitivas.

dependencias

Como podemos ver se basa un poco en la filosofía de ant de usar un fichero xml de configuración, solo que en este caso se llamará pom.xml.

Puesto que esto no pretende ser un tutorial completo sobre Maven sino que pretendo tratar el problema concreto del empaquetado del proyecto os dejo un buen tutorial sobre maven para iniciarse con ello.

El problema: Empaquetar el proyecto con sus dependencias en un único jar

Cuando el proyecto ya estaba completado solo faltaba distribuirlo y para ello lo más cómo es poner todo lo necesario dentro de un único jar, de manera que no tengas que distribuir todas las dependencias por separado. Conseguir esto me ha llevado un par de noches de madrugada y algo de desesperación, no me ha parecido que la documentación que he encontrado haya sido demasiado clara y por ello una vez que lo he conseguido creo que puedo explicar como lo he hecho para que otros no pasen por lo mismo que he pasado yo.

El proyecto en concreto ha dado varios problemas. En primer lugar es un proyecto hecho con Swing y con el asistente de Netbeans, el cual usa Matisse. Esto ya fue un problema ya que aún estando la librería necesaria (swing-layaout.jar) dentro del jar no funcionaba, al ejecutar el proyecto se obtenía esta excepción.

Otro problema fue el usar el conjunto de librerías de GeoTools que definen vario módulos en META-INF/services, de manera que al juntar todos los META-INF de las librerías usadas en un único jar estas carpetas se perdían. Y por lo tanto no funcionaba.

El proyecto también usa la librería JAI (Java Advanced Imaging) y al guardar un archivo PNG en disco también tenía otra excepción porque le faltaban datos al MANIFEST.MF del jar sobre el proveedor de la máquina virtual de Java.

El proyecto también tenía ficheros que no eran clases java como imágenes para la interfaz. Esto también provocó fallos, no se estaban incluyendo esos ficheros en el jar.

Como podéis ver son bastantes los problemas que me he encontrado y que tenía que resolver, cuando parecía que lo había conseguido aparecía un problema más 🙁

Los intentos han sido varios. El primero de ellos que encontré fue usar el plugin de maven freehep-jarjar, aquella solución no funcionó porque enseguida se hizo denotar el problema que ya he descrito al usar JAI.

El segundo intento fue usar el plugin maven-assembly, esta solución parecía bastante personalizable , aunque tediososo de configurar, teniendo que tener otro fichero de configuración aparte y además tenía bugs a la hora de incluir el classpath en el MANIFEST.MF, por no decir que tenía partes obsoletas.

Encontré un tutorial en inglés que me ayudó pero, me encontré el problema del Matisse del Netbeans y saltaba la excepción que ya os he enseñado.

Después de todos estos problemas di con la solución que a continuación os la explicaré.

La solución: Maven Shade Plugin y Maven Resources Plugin

En una de mis numerosas búsquedas vi una web que venía de la documentación de Geotools (no estaba buscando específicamente el problema de GeoTools). Especificaban el problema que ya os he comentado de la carpeta services y decían de usar el plugin Maven Shade.

Esta configuración del plugin era la solución, poniendo por supuesto la clase Main en el MANIFEST.MF para que al ejecutar el Jar se sepa que clase se debe iniciar.

Con esto ya conseguí que se solucionasen los problemas de GeoTools y los problemas de la librería de Swing-layaout que ya os he comentado.

Pero apareció otro el problema de los recursos, las imágenes y cualquier otro recurso archivo que no fuera un class no se había incluido en el jar. La interfaz no podía arrancar le faltaban las imágenes. Y además me di cuenta de que todos los ficheros de ayuda de JavaHelp tampoco se habían incluido ni un fichero de propiedades que también estaba usando.

La solución parecía ser que había que definir los recursos que usaba la aplicación, y para ello había que usar el plugin Maven Resources. Pero no era tan fácil porque si solo los definías los añadía a la raiz del jar y no era ese su sitio y además si no los excluías también añadía los ficheros java. La solución os la pongo a continuación con comentarios para solucionar los problemas que planteo. El código habrá que ponerlo dentro del build del pom.xml.

Bueno, la aplicación por lo menos ya arrancaba, pero cuando fui a usar la función que guardaba un png apareció el problema que ya os he comentado de JAI, le faltaban datos en el MANIFEST.MF. La cuestión era saber cuales le faltaban. Para añadir los datos lo hacemos dentro de la sección del manifiesto del Maven Shade Plugin, debajo de donde pusimos la clase Main.

Después de añadir estas propiedades la aplicación arrancaba y funcionaba toda su funcionabilidad.

Repasando …

Ahora que ya hemos visto todos los problemas que me surgieron y sus soluciones creo que sería interesante ver el pom.xml con todos los datos que hemos ido incluyendo en los diferentes pasos. Y a la vez comentar que esto me ha funcionado en Mac y en Windows con la versión 1.7.0_09 de la máquina virtual de Java.

El pom.xml lo he dejado lo más comentado que he podido para que sirva de ayuda.


Espero que todo esto os haya servido de ayuda y no tengáis los mismos problemas que me ha dado a mi, que ya véis que han sido bastantes.

Digo lo mismo de siempre, cualquier duda que tengáis no dudéis en dejar un comentario y haré todo lo que esté en mi mano para intentar ayudar.

Sin más que decir me despido hasta la próxima publicación 🙂


2 Comentarios

  1. Eres un crack! Me has ayudado mucho con lo de shade ya que tenía el mismo problema, ahora estoy pegándome con lo de los recuros que sigo sin que me funcione… No consigo acceder a las imágenes que tengo guardadas en el proyecto. A ver si consigo sacarlo.
    Saludos!

    • Me alegro de que te haya ayudado, por eso lo hice ya que a mi me costó varias horas, para que a los siguientes no les pasara lo mismo 🙂
      Respecto a lo de las imágenes con lo de los recursos que he puesto a mi me sirvió, mi proyecto también tenía imágenes.

      Un saludo!

Trackbacks/Pingbacks

  1. Bitacoras.com - Información Bitacoras.com... Valora en Bitacoras.com: Recientemente he estado trabajando en un proyecto Java en el cual he tenido que…

Deja un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

A %d blogueros les gusta esto: