Hacer un plugin para Maven

De ChuWiki

Crear el proyecto Maven[editar]

La mejor forma de crear un plugin para Maven es crear un proyecto Maven para el plugin. Por supuesto, no es obligatorio y podemos hacerlo como queramos, ya que un plugin Maven no es más que unas clases Java.

El comando de Maven que nos permite crear el proyecto de plugin es

mvn archetype:create
  -DgroupId=com.chuidiang.ejemplos.plugin_maven
  -DartifactId=plugin_maven
  -DarchetypeArtifactId=maven-archetype-mojo

donde groupId es el paquete que queremos que tenga nuestra clase java y artifactId es el nombre de nuestro proyecto y del jar que se generará. Lo de archetypeArtifactId es para indicar a Maven el tipo de proyecto que tiene que hacer. maven-archetype-mojo es la palabreja indicada para un plugin Maven.

Una vez ejecutado el comando, tendremos la siguiente estructura de directorios

./pom.xml
./src
./src/main
./src/main/java
./src/main/java/com
./src/main/java/com/chuidiang
./src/main/java/com/chuidiang/ejemplos
./src/main/java/com/chuidiang/ejemplos/MyMojo.java


El código java[editar]

El código java creado por Maven para MyMojo.java es el siguiente

package com.chuidiang.ejemplos.plugin_maven;
/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * Goal which touches a timestamp file.
 *
 * @goal touch
 * 
 * @phase process-sources
 */
public class MyMojo
    extends AbstractMojo
{
    /**
     * Location of the file.
     * @parameter expression="${project.build.directory}"
     * @required
     */
    private File outputDirectory;

    public void execute()
        throws MojoExecutionException
    {
        File f = outputDirectory;

        if ( !f.exists() )
        {
            f.mkdirs();
        }

        File touch = new File( f, "touch.txt" );

        FileWriter w = null;
        try
        {
            w = new FileWriter( touch );

            w.write( "touch.txt" );
        }
        catch ( IOException e )
        {
            throw new MojoExecutionException( "Error creating file " + touch, e );
        }
        finally
        {
            if ( w != null )
            {
                try
                {
                    w.close();
                }
                catch ( IOException e )
                {
                    // ignore
                }
            }
        }
    }
}

Este plugin creado por defecto simplemente escribe un fichero touch.txt en el directorio target. Aquí es donde podemos empezar a tocar el código para que haga lo que nosotros queramos que haga.


Obtener parámetros en nuestro plugin[editar]

Si observamos el código, hay en los comentarios cosas como esta

    /**
     * Location of the file.
     * @parameter expression="${project.build.directory}"
     * @required
     */
    private File outputDirectory;

La forma de que Maven le pase datos a nuestro plugin es precisamente esa. Declaramos atributos privados y en el comentario le decimos a Maven con qué tiene que inicializarlos.

El @parameter expression= inicializa nuestro atributo con lo que pongamos detrás. ${project.build.directory} es uno de las "variables" disponibles de Maven para rellenar nuestros atributos. Esta en concreto es el directorio donde maven construye las cosas, es decir, el directorio target de nuestro proyecto. En Maven Properties o parameter expressions de Maven tienes una lista de posibles "variables" que puedes poner en tus plugins.


Ejecutar nuestro plugin[editar]

Para ejecutar nuestro plugin necesitamos otro proyecto maven en cuyo pom.xml indiquemos que queremos usar nuestro nuevo plugin. Hay dos posibilidades. Una es simplemente indicar así que queremos usar nuestro plugin

...
<build>
   <plugins>
       <plugin>
          <groupId>com.chuidiang.ejemplos</groupId>
          <artifactId>plugin_maven</artifactId>
          <version>1.0-SNAPSHOT</version>
       </plugin>
       ...
   </plugins>
   ...
</build>

y luego ejecutarlo desde línea de comandos así

 mvn com.chuidiang.ejemplos:plugin_maven:1.0-SNAPSHOT:touch

La otra opción es indicar en el pom.xml que queremos que se ejecute, en qué fase y qué parte de nuestro plugin. Para ello, en el pom.xml ponemos

<build>
<plugins>
   <plugin>
      <groupId>com.chuidiang.ejemplos</groupId>
      <artifactId>plugin_maven</artifactId>
      <version>1.0-SNAPSHOT</version>
      <executions>
         <execution>
             <phase>compile</phase>
             <goals>
                 <goal>touch</goal>
             </goals>
         </execution>
      </executions>
   </plugin>
   ...
</plugins>
...
</build>

De esta forma, el "goal touch" se ejecutará siempre que se compile el proyecto. El nombre del "goal", si te fijas en el código, está en el comentario de cabecera de la clase MyMojo.java.


Subir nuestro plugin a un repositorio (deploy)[editar]

Para subir nuestro plugin a un repositorio de maven tenemos un par de problemillas que nos obligan a hacer unas pequeñas trampas. Paso a explicar los problemas.

Al crear el proyecto plugin de maven como hemos indicado, el packaging del fichero pom.xml es maven-plugin. Con este packaging, mvn install funciona correctamente: compila el jar y lo sube a nuestro repositorio maven local, por lo que podemos usar el plugin normalmente. Sin embargo, mvn deploy es menos inteligente y NO sabe qué hacer un packaging maven-plugin, dando un error.

Una primera solución es cambiar ese packaging por jar. Pero esto trae otro problema. Si el packaging es maven-plugin, al generar el jar del plugin con mvn package, se mete dentro del jar automáticamente un fichero xml que describe los goals del plugin. Sin este fichero, maven no identificará el jar como de un plugin. Así que tampoco podemos poner packaging jar.

El truco, feo, es el siguiente:

  • Dejamos el packaging como maven-plugin y hacemos un mvn install. Esto creará el jar del plugin correctamente, con su descriptor xml dentro.
  • Inmediatamente después, cambiamos el packaging a jar y hacemos el mvn deploy. Al estar el proyecto ya compilado y el jar generado, mvn deploy no recompilará nada y se limitará a subir el jar tal cual al servidor remoto.
  • Y con esto hemos terminado. El fichero .pom subido pondrá packaging jar en vez de maven-plugin, pero no parece ser importante y el plugin puede usarse bajándoselo del sitio remoto.
  • La otra opción es, en el segundo punto, en vez de cambiar el packaging, hacer un mvn deploy:deploy-file.


Configurar settings.xml y pom.xml para usar plugins remotos[editar]

Si queremos usar un plugin que hemos subido a nuestro propio repositorio remoto en otro proyecto, al no ser uno de los repositorios oficiales de maven, debemos indicarle a maven dónde está dicho repositorio.

Una opción es hacerlo en el settings.xml, opción adecuada si vamos a usar ese plugin en muchos proyectos y no tenemos excesiva intención de compartir esos proyectos con otras personas. Para ello, en el settings.xml debemos poner algo como esto

<settings>
   ...
   <profiles>
      ...
      <profile>
             <id>repo-chuidiang</id>
             <activation>
                <activeByDefault>true</activeByDefault>
             </activation>
             <pluginRepositories>
               <pluginRepository>
               <id>com.chuidiang</id>
               <name>com.chuidiang</name>
               <!-- repositorio remoto donde hemos subido el plugin -->
               <url>http://maven2.chuidiang.com</url>
               <releases>
                  <enabled>true</enabled>
               </releases>
            </pluginRepository>
         </pluginRepositories>
      </profile>
      ...   
   </profiles>
   ...
</settings>

La otra opción es hacerlo en el pom.xml. Esto es adecuado si el plugin sólo vamos a usarlo esporádicamente en algún que otro proyecto o si pensamos compartir los proyectos con otras personas, así el mismo proyecto tiene la información de dónde bajarse los plugins. En el pom.xml debems poner algo como esto

<project>
   ...
   <pluginRepositories>
      <pluginRepository>
         <id>com.chuidiang</id>
         <name>com.chuidiang</name>
         <!-- La url del repositorio maven donde esta el plugin -->
         <url>http://maven2.chuidiang.com</url>
         <releases>
            <enabled>true</enabled>
         </releases>
      </pluginRepository>
      ...
   </pluginRepositories>
   ...
</project>


Enlaces externos[editar]