Maven: cómo anular la dependencia agregada por una biblioteca

116

Aquí está mi problema genérico:

Mi proyecto P depende de A, que depende de B, que depende de C, que depende de la versión 1.0.1 de D.

Hay un problema con la versión 1.0.1 de D y quiero forzar el uso de otro módulo. No sé cómo declarar esto en los POM de mi proyecto ya que no he agregado una dependencia en D directamente. Es C quien declaró la dependencia de D.

Importante: En este caso, no solo se cambia la versión, sino también el grupo y el artefacto. Entonces, no se trata solo de anular la versión de la dependencia, sino de excluir un módulo e incluir otro.

En el caso concreto, D es StAX cuyo 1.0.1 tiene un error . Según las notas en el error, "los problemas se resolvieron reemplazando el stax-api-1.0.1 (maven GroupId = stax) por stax-api-1.0-2 (maven GroupId = javax.xml.stream)", así que Estoy intentando precisamente eso.

Por lo tanto, D = stax: stax-api: jar: 1.0.1 y C = org.apache.xmlbeans: xmlbeans: jar: 2.3.0

Estoy usando maven 2.0.9 en caso de que importe.

Salida de la dependencia de mvn: árbol "

mvn dependency:tree
[..snip..]
[INFO] +- org.apache.poi:poi-ooxml:jar:3.6:compile
[INFO] |  +- org.apache.poi:poi-ooxml-schemas:jar:3.6:compile
[INFO] |  |  +- org.apache.xmlbeans:xmlbeans:jar:2.3.0:compile
[INFO] |  |  |  \- stax:stax-api:jar:1.0.1:compile

En el POM de mi proyecto tengo la siguiente dependencia de "A":

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.6</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.6</version>
</dependency>

Gracias por adelantado.

wishihadabettername
fuente

Respuestas:

100

Simplemente especifique la versión en su pom actual. La versión especificada aquí anulará a otra.

Forzar una versión
Siempre se respetará una versión si se declara en el POM actual con una versión particular; sin embargo, debe tenerse en cuenta que esto también afectará a otros poms posteriores si se depende del uso de dependencias transitivas.


Recursos:

Colin Hebert
fuente
5
no está claro cómo puedo especificar la versión ya que no declaro una dependencia en D. Además, el primer enlace que proporcionó tiene "Este documento describe el resto de los requisitos para la administración de dependencias que aún NO se han implementado para Maven 2.0, especialmente en lo que respecta a las dependencias transitivas ". en la cima.
wishihadabettername
@wishihadabettername, como se dice en el otro documento: "Podría agregar explícitamente una dependencia a D 2.0 en A para forzar el uso de D 2.0"
Colin Hebert
1
De hecho, duplica la misma entrada <dependency> en su propio pom. En su dependencia, especifique una <versión> que desee. Eso anulará cualquier versión utilizada por dependencias "más profundas".
Keith Tyler
27

Alternativamente, puede excluir la dependencia que no desea. STAX está incluido en JDK 1.6, por lo que si está utilizando 1.6, puede excluirlo por completo.

Mi ejemplo a continuación es un poco incorrecto para usted: solo necesita una de las dos exclusiones, pero no estoy seguro de cuál. Hay otras versiones de Stax flotando, en mi ejemplo a continuación, estaba importando A, que importó B, que importó C y D, que cada uno (a través de dependencias aún más transitivas) importó diferentes versiones de Stax. Entonces, en mi dependencia de 'A', excluí ambas versiones de Stax.

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>
escocés
fuente
1
Es necesario tener en cuenta que esta dependencia transitiva se puede utilizar y la exclusión puede provocar un error de compilación si es necesario.
Bernhard Colby
Si está utilizando un JDK moderno (es decir, 1.6+) y necesita la versión mucho más antigua de stax incluida a través de una dependencia transitiva, probablemente se encontrará con todo tipo de problemas terribles con el cargador de clases en tiempo de ejecución. Mi consejo: usa el del JDK. Si obtiene un "error de compilación", está confiando en una API antigua de alguna forma que debería actualizarse. O: retroceda su JDK a 1.5. Buena suerte con eso.
Escocia
11

Lo que ponga dentro de la </dependencies>etiqueta del root pom será incluido por todos los módulos secundarios del root pom. Si todos sus módulos usan esa dependencia, este es el camino a seguir.

Sin embargo, si solo 3 de cada 10 de sus módulos secundarios utilizan alguna dependencia, no desea que esta dependencia se incluya en todos sus módulos secundarios. En ese caso, puede poner la dependencia dentro de </dependencyManagement>. Esto asegurará que cualquier módulo hijo que necesite la dependencia debe declararlo en su propio archivo pom, pero usarán la misma versión de esa dependencia como se especifica en su </dependencyManagement>etiqueta.

También puede utilizar </dependencyManagement>para modificar la versión utilizada en dependencias transitivas, porque la versión declarada en el archivo pom superior es la que se utilizará. Esto puede ser útil si su proyecto A incluye un proyecto externo B v1.0 que incluye otro proyecto externo C v1.0. A veces sucede que se encuentra una brecha de seguridad en el proyecto C v1.0 que se corrige en la v1.1, pero los desarrolladores de B tardan en actualizar su proyecto para usar la v1.1 de C. En ese caso, simplemente puede declarar una dependencia de C v1.1 en el pom raíz de su proyecto dentro de `, y todo estará bien (asumiendo que B v1.0 aún podrá compilar con C v1.1).

Kent Munthe Caspersen
fuente
10

También tuve problemas para anular una dependencia en una biblioteca de terceros. Usé el enfoque de scot con la exclusión, pero también agregué la dependencia con la versión más nueva en el pom. (Usé Maven 3.3.3)

Entonces, para el ejemplo de stAX, se vería así:

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>

<dependency>
    <groupId>javax.xml.stream</groupId>
    <artifactId>stax-api</artifactId>
    <version>1.0-2</version>
</dependency>
Patrick Koorevaar
fuente
1

La respuesta aceptada es correcta, pero me gustaría agregar mis dos centavos. Me encontré con un problema en el que tenía un proyecto A que tenía un proyecto B como dependencia. Ambos proyectos usan slf4j pero el proyecto B usa log4j mientras que el proyecto A usa logback. El proyecto B usa slf4j 1.6.1, mientras que el proyecto A usa slf4j 1.7.5 (debido a la dependencia de logback 1.2.3 ya incluida).

El problema: el Proyecto A no pudo encontrar una función que exista en slf4j 1.7.5, después de verificar la pestaña de jerarquía de dependencias de eclipe, descubrí que durante la compilación estaba usando slf4j 1.6.1 del proyecto B, en lugar de usar slf4j 1.7.5 de logback .

Resolví el problema cambiando el orden de las dependencias en el proyecto A pom, cuando moví la entrada del proyecto B debajo de la entrada de inicio de sesión, maven comenzó a construir el proyecto usando slf4j 1.7.5.

Editar: Agregar la dependencia slf4j 1.7.5 antes de que la dependencia del Proyecto B también funcionara.

Fernando Maia
fuente