java - ¿Hay alguna forma de excluir artefactos heredados de un POM padre?
maven-2 pom.xml (7)
Los artefactos de las dependencias se pueden excluir al declarar un elemento <exclusions>
dentro de una <dependency>
Pero en este caso es necesario excluir un artefacto heredado de un proyecto principal. A continuación se incluye un fragmento del POM en discusión:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>ALL-DEPS</artifactId>
<version>1.0</version>
<scope>provided</scope>
<type>pom</type>
</dependency>
</dependencies>
</project>
artefacto base
, depende de javax.mail:mail-1.4.jar
, y ALL-DEPS
depende de otra versión de la misma biblioteca. Debido al hecho de que mail.jar
de ALL-DEPS
existe en el entorno de ejecución, aunque no se haya exportado, colisiona con mail.jar
que existe en el elemento primario, que tiene un ámbito de compile
.
Una solución podría ser deshacerse de mail.jar del POM padre, pero la mayoría de los proyectos que heredan base lo necesitan (al igual que una dependencia de transtive para log4j). Entonces, lo que me gustaría hacer es simplemente excluir la biblioteca de los padres del proyecto hijo , ya que podría hacerse si la base
fuera una dependencia y no el padre principal:
...
<dependency>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<type>pom<type>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
...
No use un pom padre
Esto puede sonar extremo, pero del mismo modo el "infierno hereditario" es una razón por la que algunas personas le dan la espalda a la Programación Orientada a Objetos, o de la misma manera que los cirujanos lo mantienen vivo con cirugía de derivación coronaria: elimine el bloque problemático <parent>
y copie y pegue cualesquiera <dependencies>
que necesite.
Se debe ignorar la suposición de que la división de poms en padres e hijos para "reutilizar" y "evitar el redunancy" debe ignorarse y debe atender sus necesidades inmediatas primero. La redundancia tiene sus ventajas, a saber, la independencia de las complicaciones externas.
Esto es más fácil de lo que parece si generas el pom efectivo (eclipse lo proporciona pero puedes generarlo desde la línea de comando).
Ejemplo
Quiero usar logback
pero mi padre pom usa log4j
y no quiero ir y tengo que presionar la dependencia de otros niños en log4j hacia abajo en sus propios archivos pom.xml
para que el mío no tenga obstrucciones.
Puede obtener mucho de un padre, pero a veces su padre no sabe lo que es bueno para usted.
¿Has intentado declarar explícitamente la versión de mail.jar que quieres? La resolución de dependencia de Maven debería usar esto para la resolución de dependencia sobre todas las demás versiones.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>VERSION-#</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>ALL-DEPS</artifactId>
<version>1.0</version>
<scope>provided</scope>
<type>pom</type>
</dependency>
</dependencies>
</project>
Algunas ideas:
Tal vez simplemente no podría heredar del padre en ese caso (y declarar una dependencia en
base
con la exclusión). No es útil si tienes muchas cosas en el pom padre.Otra cosa para probar sería declarar el artefacto de
mail
con la versión requerida porALL-DEPS
bajo laALL-DEPS
dependencyManagement
en el pom padre para forzar la convergencia (aunque no estoy seguro de que esto resuelva el problema del alcance).
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>???</version><!-- put the "right" version here -->
</dependency>
</dependencies>
</dependencyManagement>
- O podría excluir la dependencia del
mail
de log4j si no está utilizando las funciones que dependen de él (y esto es lo que yo haría):
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
</dependency>
- O puede volver a la versión 1.2.14 de log4j en lugar de la versión 1.2.15 hereje (¿por qué no marcan las dependencias anteriores como opcional ?!).
Cuando llamas a un paquete pero no quieres algunas de sus dependencias, puedes hacer algo como esto (en este caso, no quería que se agregara el log4j anterior porque necesitaba usar el más reciente):
<dependency>
<groupId>package</groupId>
<artifactId>package-pk</artifactId>
<version>${package-pk.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- LOG4J -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
Esto funciona para mí ... pero soy bastante nuevo en Java / Maven, así que quizás no sea óptimo.
La mejor apuesta es hacer que las dependencias que no siempre deseas heredar sean transitivas.
Puede hacer esto marcándolos en el pom padre con el alcance provisto.
Si aún desea que el padre administre las versiones de estos productos, puede usar la etiqueta <dependencyManagement>
para configurar las versiones que desee sin heredarlas explícitamente o pasar esa herencia a los elementos secundarios.
Puede agrupar sus dependencias dentro de un proyecto diferente con packaging pom
como se describe en Sonatypes Best Practices :
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>
y hacer referencia a ellos desde su parent-pom (mire la dependencia <type>pom</type>
):
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
Su proyecto hijo hereda este parent-pom como antes. Pero ahora, la dependencia de correo puede ser excluida en el proyecto hijo dentro del bloque de dependencyManagement
gestión:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Redefina la dependencia (en el pom hijo) con el sistema de scope
apuntando a un jar vacío:
<dependency>
<groupId>dependency.coming</groupId>
<artifactId>from.parent</artifactId>
<version>0</version>
<scope>system</scope>
<systemPath>${project.basedir}/empty.jar</systemPath>
</dependency>
El contenedor puede contener solo un archivo vacío:
touch empty.txt
jar cvf empty.txt