Een versiebotsing van artefacten in Maven oplossen

1. Overzicht

Maven-projecten met meerdere modules kunnen complexe afhankelijkheidsgrafieken hebben. Deze kunnen ongebruikelijke resultaten hebben, naarmate de modules meer van elkaar importeren.

In deze tutorial zullen we zien hoe versiebotsing van artefacten in Maven oplossen.

We beginnen met een project met meerdere modules waarin we opzettelijk verschillende versies van hetzelfde artefact hebben gebruikt. Vervolgens zullen we zien hoe we kunnen voorkomen dat u de verkeerde versie van een artefact krijgt met uitsluitings- of afhankelijkheidsbeheer.

Ten slotte zullen we proberen de m te gebruikenaven-enforcer-plugin om dingen gemakkelijker te controleren, door het gebruik van transitieve afhankelijkheden te verbieden.

2. Versiebotsing van artefacten

Elke afhankelijkheid die we in ons project opnemen, kan naar andere artefacten verwijzen. Maven kan deze artefacten automatisch binnenbrengen, ook wel transitieve afhankelijkheden genoemd. Versiebotsing vindt plaats wanneer meerdere afhankelijkheden naar hetzelfde artefact linken, maar verschillende versies gebruiken.

Als gevolg hiervan kunnen er fouten optreden in onze applicaties zowel in de compilatiefase als tijdens runtime.

2.1. Projectstructuur

Laten we een projectstructuur met meerdere modules definiëren om mee te experimenteren. Ons project bestaat uit een versie-botsing ouder- en drie kindermodules:

versie-botsing project-a project-b project-botsing 

De pom.xml voor project-a en project-b zijn bijna identiek. Het enige verschil is de versie van de com.google.guava artefact waarvan ze afhankelijk zijn. Vooral, project-a gebruikt versie 22.0:

  com.google.guava guave 22.0 

Maar, project-b gebruikt de nieuwere versie, 29.0-jre:

  com.google.guava guave 29.0-jre 

De derde module, project-botsing, hangt af van de andere twee:

  com.baeldung project-a 0.0.1-SNAPSHOT com.baeldung project-b 0.0.1-SNAPSHOT 

Dus welke versie van guave zal beschikbaar zijn voor project-botsing?

2.2. Functies gebruiken van een specifieke afhankelijkheidsversie

We kunnen erachter komen welke afhankelijkheid wordt gebruikt door een eenvoudige test te maken in het project-botsing module die gebruikmaakt van de Futures.immediateVoidFuture methode van guave:

@Test openbare leegte whenVersionCollisionDoesNotExist_thenShouldCompile () {assertThat (Futures.immediateVoidFuture (), notNullValue ()); }

Deze methode is alleen beschikbaar via de 29.0-jre versie. We hebben dit geërfd van een van de andere modules, maar we kunnen onze code alleen compileren als we de transitieve afhankelijkheid hebben van project-b.

2.3. Compilatiefout veroorzaakt door versiebotsing

Afhankelijk van de volgorde van afhankelijkheden in het project-botsing module, in bepaalde combinaties retourneert Maven een compilatiefout:

[FOUT] Kan doel org.apache.maven.plugins niet uitvoeren: maven-compiler-plugin: 3.8.1: testCompile (standaard-testCompile) op projectproject-botsing: Compilatiefout [ERROR] / tutorials / maven-all / version -collision / project-collision / src / test / java / com / baeldung / version / collision / VersionCollisionUnitTest.java: [12,27] kan symbool niet vinden [ERROR] symbool: methode instantVoidFuture () [FOUT] locatie: class com. google.common.util.concurrent.Futures

Dat is het resultaat van de versiebotsing van de com.google.guava artefact. Standaard kiest Maven voor afhankelijkheden op hetzelfde niveau in een afhankelijkheidsstructuur de eerste bibliotheek die het vindt. In ons geval beide com.google.guava afhankelijkheden zijn op dezelfde hoogte en de oudere versie is gekozen.

2.4. Gebruik makend van maven-afhankelijkheid-plugin

De maven-afhankelijkheid-plugin is een zeer nuttige tool om alle afhankelijkheden en hun versies te presenteren:

% mvn afhankelijkheid: tree -Dverbose [INFO] --- maven-dependency-plugin: 2.8: tree (default-cli) @ project-collision --- [INFO] com.baeldung: project-collision: jar: 0.0.1 -SNAPSHOT [INFO] + - com.baeldung: project-a: jar: 0.0.1-SNAPSHOT: compileren [INFO] | \ - com.google.guava: guava: jar: 22.0: compileer [INFO] \ - com.baeldung: project-b: jar: 0.0.1-SNAPSHOT: compileer [INFO] \ - (com.google.guava: guava : jar: 29.0-jre: compile - weggelaten wegens conflict met 22.0)

De -Dverbose vlag geeft conflicterende artefacten weer. In feite hebben we een com.google.guava afhankelijkheid in twee versies: 22.0 en 29.0-jre. Dit laatste is degene die we zouden willen gebruiken in de project-botsing module.

3. Een transitieve afhankelijkheid uitsluiten van een artefact

Een manier om een ​​versiebotsing op te lossen is door het verwijderen van een conflicterende transitieve afhankelijkheid van specifieke artefacten. In ons voorbeeld willen we de com.google.guava bibliotheek tijdelijk toegevoegd vanuit het project-a artefact.

Daarom kunnen we het uitsluiten in de project-botsing pom:

  com.baeldung project-a 0.0.1-SNAPSHOT com.google.guava guave com.baeldung project-b 0.0.1-SNAPSHOT 

Nu, wanneer we het afhankelijkheid: boom commando, kunnen we zien dat het er niet meer is:

% mvn afhankelijkheid: tree -Dverbose [INFO] --- maven-dependency-plugin: 2.8: tree (default-cli) @ project-collision --- [INFO] com.baeldung: project-collision: jar: 0.0.1 -SNAPSHOT [INFO] \ - com.baeldung: project-b: jar: 0.0.1-SNAPSHOT: compileren [INFO] \ - com.google.guava: guava: jar: 29.0-jre: compileren

Hierdoor eindigt de compilatiefase foutloos en kunnen we de klassen en methoden uit version gebruiken 29.0-jre.

4. Gebruik de afhankelijkheidsbeheer Sectie

Maven's afhankelijkheidsbeheer sectie is een mechanisme voor het centraliseren van afhankelijkheidsinformatie. Een van de handigste functies is het beheren van versies van artefacten die worden gebruikt als transitieve afhankelijkheden.

Laten we met dat in gedachten een afhankelijkheidsbeheer configuratie in onze ouder pom:

   com.google.guava guave 29.0-jre 

Als gevolg hiervan zorgt Maven ervoor dat versie 29.0-jre van com.google.guava artefact in alle onderliggende modules:

% mvn afhankelijkheid: tree -Dverbose [INFO] --- maven-dependency-plugin: 2.8: tree (default-cli) @ project-collision --- [INFO] com.baeldung: project-collision: jar: 0.0.1 -SNAPSHOT [INFO] + - com.baeldung: project-a: jar: 0.0.1-SNAPSHOT: compileren [INFO] | \ - com.google.guava: guava: jar: 29.0-jre: compileren (versie beheerd vanaf 22.0) [INFO] \ - com.baeldung: project-b: jar: 0.0.1-SNAPSHOT: compileren [INFO] \ - (com.google.guava: guava: jar: 29.0-jre: compileren - versie beheerd vanaf 22.0; weggelaten voor duplicaat)

5. Voorkom onbedoelde transitieve afhankelijkheden

De maven-enforcer-plugin biedt veel ingebouwde regels die vereenvoudig het beheer van een project met meerdere modules. Een van hen verbiedt het gebruik van klassen en methoden van transitieve afhankelijkheden.

Expliciete afhankelijkheidsverklaring verwijdert de mogelijkheid van versiebotsing van artefacten. Laten we de maven-enforcer-plugin met die regel voor onze ouder pom:

 org.apache.maven.plugins maven-enforcer-plugin 3.0.0-M3 afdwingen-verboden-afhankelijkheden afdwingen 

Als gevolg hiervan moeten we nu expliciet de com.google.guava artefact in ons project-botsing module als we deze zelf willen gebruiken. We moeten de te gebruiken versie specificeren of instellen afhankelijkheidsbeheer in de ouder pom.xml. Dit maakt ons project meer foutbestendig, maar vereist dat we explicieter zijn in ons pom.xml bestanden.

6. Conclusie

In dit artikel hebben we gezien hoe u een versiebotsing van artefacten in Maven kunt oplossen.

Eerst hebben we een voorbeeld onderzocht van een versiebotsing in een project met meerdere modules.

Vervolgens hebben we laten zien hoe u transitieve afhankelijkheden in het pom.xml. We hebben gekeken hoe afhankelijkheidsversies kunnen worden beheerd met de afhankelijkheidsbeheer sectie in de ouder pom.xml.

Ten slotte hebben we de maven-enforcer-plugin om het gebruik van transitieve afhankelijkheden te verbieden om elke module te dwingen zijn eigen controle over te nemen.

Zoals altijd is de code die in dit artikel wordt getoond, beschikbaar op GitHub.