Apache Maven

Maven clean plugin

11 min lectura José Miguel

Cuando trabajamos en Maven es muy habitual necesitar agregar y configurar complementos (plugins) al mismo para poder usarlos para realizar tareas de compilación necesarias. Maven usa una arquitectura de plugins, y a excepción de las funcionalidades prioritarias, todas las tareas en Maven se realizan mediante plugins. Es sobre lo último que centraremos en Maven clean plugin.

Cuando se construye un proyecto, es importante asegurarse de que no se está afectado anteriormente por artefactos de una construcción anterior. Por lo general, las herramientas de compilación guardan artefactos en una carpeta bien definida llamada target, dependiendo del directorio de trabajo del proyecto. Antes de una nueva compilación, esta carpeta generalmente se elimina.

Cuando se invoca a la fase clean, Maven borra automáticamente el resultado de la compilación anterior (en Maven se conoce a la fase de limpieza como clean). Para ello se utiliza el plugin Maven Clean. El plugin maven-clean-plugin se encarga de esta tarea: limpia el directorio de trabajo que ya veremos que se llama target.

Como clean es un ciclo de vida aparte del ciclo de vida estándar (predeterminado/default), clean debe llamarse explícitamente antes del ciclo de vida predeterminado (default) si necesitas asegurarte de que se elimine el directorio de índices.

¿Qué contiene el directorio target?

Antes de profundizar en el plugin, es importante entender qué genera Maven dentro de la carpeta target. Cuando ejecutamos una compilación, Maven deposita en este directorio todos los artefactos resultantes del proceso:

  • classes/ — Contiene los archivos .class compilados a partir del código fuente ubicado en src/main/java.
  • test-classes/ — Contiene los archivos .class compilados de los tests ubicados en src/test/java.
  • surefire-reports/ — Reportes generados por la ejecución de los tests unitarios (formato XML y TXT).
  • maven-archiver/ — Metadatos utilizados por Maven para empaquetar el artefacto final.
  • Artefacto final — El archivo .jar, .war o .ear resultante de la fase package, con el nombre definido por artifactId y version.

Con el tiempo, estos artefactos pueden quedar desactualizados si no se limpia el directorio antes de una nueva compilación. Por ejemplo, si renombramos una clase y no ejecutamos clean, el archivo .class antiguo seguirá existiendo junto al nuevo, lo que puede provocar errores difíciles de diagnosticar. De ahí la importancia del plugin maven-clean-plugin.

Maven clean plugin en la práctica

Vamos en la práctica a ver cómo trabajar con el plugin maven-clean-plugin. Para ello vamos a crear un proyecto nuevo con el siguiente comando:

mvn archetype:generate -DgroupId=com.josemtech.maven \
  -DartifactId=mi-proyecto \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.5 \
  -DinteractiveMode=false

Para poder ejecutar el código anterior necesitamos tener instalado Maven en nuestra computadora y además tener bien configuradas las variables de entorno para que se reconozca el comando mvn.

Si tenemos todos los requisitos y ejecutamos el comando anterior, deberíamos ver una salida similar a la siguiente:

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> archetype:3.2.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO] <<< archetype:3.2.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO] --- archetype:3.2.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.josemtech.maven
[INFO] Parameter: artifactId, Value: mi-proyecto
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.josemtech.maven
[INFO] Parameter: packageInPathFormat, Value: com/josemtech/maven
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.josemtech.maven
[INFO] Parameter: groupId, Value: com.josemtech.maven
[INFO] Parameter: artifactId, Value: mi-proyecto
[INFO] Project created from Archetype in dir: /Users/jose/Desktop/test-maven/mi-proyecto
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.892 s
[INFO] Finished at: 2023-05-18T23:07:00-05:00
[INFO] ------------------------------------------------------------------------

Si nos desplazamos dentro de la carpeta del proyecto observaremos cómo no existe la carpeta target. Para generar los artefactos de este proyecto y que aparezca la carpeta target vamos a ejecutar mvn package.

Ahora se ha generado el directorio target como se observa a continuación:

mi-proyecto/
├── pom.xml
├── src/
└── target/

Ahora ya podemos ejecutar el comando mvn clean y veamos cómo este elimina la carpeta target del proyecto. Deberíamos ver en el terminal el siguiente resultado:

[INFO] --- clean:3.1.0:clean (default-clean) @ mi-proyecto ---
[INFO] Deleting /Users/jose/Desktop/test-maven/mi-proyecto/target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.779 s
[INFO] Finished at: 2023-05-18T23:18:12-05:00
[INFO] ------------------------------------------------------------------------

Para este punto ya no deberíamos tener la carpeta target en la carpeta de nuestro proyecto:

mi-proyecto/
├── pom.xml
└── src/

Podría darse el caso de que deseemos que cada vez que construyamos nuestro proyecto nos aseguremos que se borre la carpeta target antes de construir el proyecto. Veamos a continuación cómo podemos ejecutar automáticamente el plugin clean durante la compilación del proyecto.

Ejecutar el plugin clean automáticamente

Para poder ejecutar el plugin clean automáticamente durante la compilación del proyecto necesitamos definir el plugin con algunos parámetros en nuestro archivo pom. Veamos la forma en que podemos agregarlo:

<build>
  <plugins>
    <plugin>
      <artifactId>maven-clean-plugin</artifactId>
      <version>3.1.0</version>
      <executions>
        <execution>
          <id>auto-clean</id>
          <phase>initialize</phase>
          <goals>
            <goal>clean</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Ahora ejecutaremos de nuevo el comando mvn package. Lo que hemos hecho es solicitarle a Maven que ejecute el goal clean durante la fase de inicialización del proyecto. Además podemos identificar esta ejecución con el id auto-clean como se muestra a continuación:

[INFO] ------------------< com.josemtech.maven:mi-proyecto >-------------------
[INFO] Building mi-proyecto 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.1.0:clean (auto-clean) @ mi-proyecto ---
[INFO]
[INFO] --- resources:3.0.2:resources (default-resources) @ mi-proyecto ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/jose/Desktop/test-maven/mi-proyecto/src/main/resources
[INFO]
[INFO] --- compiler:3.8.0:compile (default-compile) @ mi-proyecto ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/jose/Desktop/test-maven/mi-proyecto/target/classes
[INFO]
[INFO] --- resources:3.0.2:testResources (default-testResources) @ mi-proyecto ---

Eliminar carpetas adicionales con maven clean plugin

Sería de mucha utilidad que pudiéramos eliminar carpetas adicionales, es decir, otras carpetas que no sean la carpeta target durante la ejecución del plugin clean, veamos cómo podemos lograr esto.

Para poder eliminar carpetas además de la carpeta target debemos incluir las siguientes líneas en el pom:

<build>
  <plugins>
    <plugin>
      <artifactId>maven-clean-plugin</artifactId>
      <version>3.1.0</version>
      <executions>
        <execution>
          <id>auto-clean</id>
          <phase>initialize</phase>
          <goals>
            <goal>clean</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <filesets>
          <fileset>
            <directory>borrar</directory>
          </fileset>
        </filesets>
      </configuration>
    </plugin>
  </plugins>
</build>

Creamos una carpeta llamada borrar dentro de nuestro proyecto y lo que deseamos es que cuando se ejecute el plugin clean se borre también esta carpeta.

mi-proyecto/
├── borrar/
├── pom.xml
├── src/
└── target/

Ejecutamos nuevamente el comando mvn package y deberíamos ver un resultado como el siguiente en nuestro terminal:

[INFO] ------------------< com.josemtech.maven:mi-proyecto >-------------------
[INFO] Building mi-proyecto 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.1.0:clean (auto-clean) @ mi-proyecto ---
[INFO] Deleting /Users/jose/Desktop/test-maven/mi-proyecto/target
[INFO] Deleting /Users/jose/Desktop/test-maven/mi-proyecto/borrar (includes = [], excludes = [])
[INFO]
[INFO] --- resources:3.0.2:resources (default-resources) @ mi-proyecto ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/jose/Desktop/test-maven/mi-proyecto/src/main/resources

Observemos cómo se han borrado las carpetas target y borrar cuando hemos realizado un mvn package, debemos recordar que esto sucede porque estamos ejecutando el plugin en la fase de inicialización.

Opciones avanzadas de filesets

El elemento <filesets> ofrece más control del que vimos en el ejemplo anterior. Además de especificar un directorio completo, podemos utilizar <includes> y <excludes> para filtrar exactamente qué archivos o patrones eliminar. Esto resulta útil cuando no queremos borrar todo el contenido de una carpeta, sino solo ciertos tipos de archivo.

Por ejemplo, si queremos eliminar únicamente los archivos .log dentro de una carpeta llamada logs, pero conservar el resto de archivos, podemos configurar el plugin de la siguiente forma:

<configuration>
  <filesets>
    <fileset>
      <directory>logs</directory>
      <includes>
        <include>**/*.log</include>
      </includes>
    </fileset>
  </filesets>
</configuration>

También podemos combinar <includes> con <excludes> para crear reglas más precisas. Por ejemplo, eliminar todos los archivos temporales excepto un archivo de configuración específico:

<configuration>
  <filesets>
    <fileset>
      <directory>temp</directory>
      <includes>
        <include>**/*</include>
      </includes>
      <excludes>
        <exclude>config.properties</exclude>
      </excludes>
    </fileset>
  </filesets>
</configuration>

Los patrones utilizan la sintaxis estándar de Ant: * coincide con cualquier secuencia de caracteres dentro de un nivel de directorio, y ** coincide con cualquier secuencia de directorios.

Diferencia entre mvn clean y mvn clean package

Una duda muy común entre desarrolladores que están comenzando con Maven es la diferencia entre ejecutar mvn clean solo y ejecutar mvn clean package.

La clave está en entender que Maven tiene tres ciclos de vida independientes:

  1. clean — Se encarga de eliminar los artefactos de compilaciones anteriores.
  2. default — Es el ciclo principal que incluye las fases validate, compile, test, package, verify, install y deploy.
  3. site — Genera la documentación del proyecto.

Cuando ejecutamos mvn clean, únicamente invocamos el ciclo de vida clean, que ejecuta la fase pre-clean y luego clean (eliminando el directorio target). El proyecto no se vuelve a compilar.

Cuando ejecutamos mvn clean package, estamos invocando dos ciclos de vida en secuencia: primero el ciclo clean (que borra target) y luego el ciclo default hasta la fase package (que compila, ejecuta tests y empaqueta el artefacto). Esto garantiza una compilación completamente limpia.

La recomendación general es utilizar siempre mvn clean antes de cualquier fase del ciclo default cuando queremos asegurarnos de que no hay artefactos residuales. Los comandos más habituales son:

  • mvn clean compile — Limpia y compila el código fuente.
  • mvn clean test — Limpia, compila y ejecuta los tests.
  • mvn clean package — Limpia, compila, ejecuta tests y genera el artefacto empaquetado.
  • mvn clean install — Limpia, compila, ejecuta tests, empaqueta e instala en el repositorio local.

Errores comunes al no usar clean

Omitir la ejecución de clean antes de compilar puede parecer inofensivo, pero en la práctica puede provocar problemas difíciles de diagnosticar:

  • Clases huérfanas: Si renombramos o eliminamos una clase Java y no ejecutamos clean, el archivo .class antiguo permanece en target/classes. Esto puede causar errores de compilación confusos o, peor aún, que el programa se ejecute usando la clase obsoleta sin que nos demos cuenta.
  • Tests falsos positivos: Si un test fue eliminado del código fuente pero su .class compilado sigue en target/test-classes, Maven podría ejecutarlo igualmente, dando resultados engañosos.
  • Conflictos de recursos: Archivos de configuración (como application.properties o archivos XML) que fueron modificados o eliminados pueden seguir presentes en su versión anterior dentro de target, causando comportamientos inesperados en tiempo de ejecución.
  • Artefactos con contenido obsoleto: El .jar o .war generado podría incluir clases y recursos que ya no forman parte del proyecto, incrementando su tamaño innecesariamente y potencialmente introduciendo vulnerabilidades de seguridad.

La regla práctica es sencilla: si algo no funciona como esperas después de un cambio, ejecuta mvn clean y vuelve a compilar. En entornos de integración continua (CI/CD), lo habitual es que el pipeline siempre comience con mvn clean para garantizar builds reproducibles.

José Miguel Moya Curbelo
José Miguel Moya Curbelo
Senior Data Engineer & Big Data Instructor

MSc Applied Mathematics · AWS Cloud Practitioner · SCRUM Master. Especializado en arquitecturas de datos de alto rendimiento con Apache Spark, Snowflake, Python y Scala.

Conectar en LinkedIn

Artículos Relacionados