Sådan løses en versionskollision af artefakter i Maven

1. Oversigt

Multimodul Maven-projekter kan have komplekse afhængighedsgrafer. Disse kan have usædvanlige resultater, jo mere importeres modulerne fra hinanden.

I denne vejledning ser vi, hvordan man gør det løse versionskollision af artefakter i Maven.

Vi starter med et multimodulprojekt, hvor vi bevidst har brugt forskellige versioner af den samme artefakt. Derefter ser vi, hvordan vi kan forhindre, at man får den forkerte version af en artefakt med enten eksklusion eller afhængighedsstyring.

Endelig prøver vi at bruge maven-enforcer-plugin at gøre tingene nemmere at kontrollere ved at forbyde brugen af ​​transitive afhængigheder.

2. Version kollision af artefakter

Hver afhængighed, som vi inkluderer i vores projekt, kan linke til andre artefakter. Maven kan automatisk indbringe disse artefakter, også kaldet transitive afhængigheder. Versionskollision sker, når flere afhængigheder linker til den samme artefakt, men bruger forskellige versioner.

Som et resultat kan der være fejl i vores applikationer både i kompileringsfasen og også i løbetid.

2.1. Projektstruktur

Lad os definere en multi-modul projektstruktur at eksperimentere med. Vores projekt består af en version-kollision forældermoduler og tre børnemoduler:

version-kollision projekt-et projekt-b projekt-kollision 

Det pom.xml til projekt-a og projekt-b er næsten identiske. Den eneste forskel er versionen af com.google.guava artefakt, som de er afhængige af. I særdeleshed, projekt-a bruger version 22.0:

  com.google.guava guava 22.0 

Men, projekt-b bruger den nyere version, 29,0-jre:

  com.google.guava guava 29.0-jre 

Det tredje modul, projekt-kollision, afhænger af de to andre:

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

Så hvilken version af guava vil være tilgængelig for projekt-kollision?

2.2. Brug af funktioner fra specifik afhængighedsversion

Vi kan finde ud af, hvilken afhængighed der bruges ved at oprette en simpel test i projekt-kollision modul, der bruger Futures.immediateVoidFuture metode fra guava:

@Test offentlig ugyldig nårVersionCollisionDoesNotExist_thenShouldCompile () {assertThat (Futures.immediateVoidFuture (), notNullValue ()); }

Denne metode er kun tilgængelig fra 29,0-jre version. Vi har arvet dette fra et af de andre moduler, men vi kan kun kompilere vores kode, hvis vi har den transitive afhængighed fra projekt-b.

2.3. Kompileringsfejl forårsaget af versionskollision

Afhængig af rækkefølgen af ​​afhængigheder i projekt-kollision modul, i visse kombinationer returnerer Maven en kompileringsfejl:

[FEJL] Kunne ikke udføre mål org.apache.maven.plugins: maven-compiler-plugin: 3.8.1: testCompile (standard-testCompile) ved projektprojektkollision: Kompileringsfejl [FEJL] / tutorials / maven-all / version -kollision / projektkollision / src / test / java / com / baeldung / version / kollision / VersionCollisionUnitTest.java: [12,27] kan ikke finde symbol [FEJL] symbol: metode øjeblikkeligVoidFuture () [FEJL] placering: klasse com. google.common.util.concurrent.Futures

Det er resultatet af versionens kollision med com.google.guava artefakt. For afhængigheder på samme niveau i et afhængighedstræ vælger Maven som standard det første bibliotek, det finder. I vores tilfælde begge com.google.guava afhængigheder er i samme højde, og den ældre version vælges.

2.4. Ved brug af maven-afhængigheds-plugin

Det maven-afhængigheds-plugin er et meget nyttigt værktøj til at præsentere alle afhængigheder og deres versioner:

% mvn afhængighed: træ -Dverbose [INFO] --- maven-afhængighed-plugin: 2.8: træ (standard-cli) @ projektkollision --- [INFO] com.baeldung: projektkollision: jar: 0.0.1 -SNAPSHOT [INFO] + - com.baeldung: projekt-a: jar: 0.0.1-SNAPSHOT: kompil [INFO] | \ - com.google.guava: guava: jar: 22.0: kompilere [INFO] \ - com.baeldung: projekt-b: jar: 0.0.1-SNAPSHOT: kompilere [INFO] \ - (com.google.guava: guava : jar: 29.0-jre: compile - udeladt for konflikt med 22.0)

Det -Dverbose flag viser modstridende artefakter. Faktisk har vi en com.google.guava afhængighed i to versioner: 22.0 og 29.0-jre. Sidstnævnte er den, vi gerne vil bruge i projekt-kollision modul.

3. Udelukkelse af en transitiv afhængighed fra en artefakt

En måde at løse en versionskollision på er fjernelse af en modstridende transitiv afhængighed fra specifikke artefakter. I vores eksempel ønsker vi ikke at have com.google.guava bibliotek tilføjet transitivt fra projekt-a artefakt.

Derfor kan vi udelukke det i projekt-kollision pom:

  com.baeldung projekt-a 0.0.1-SNAPSHOT com.google.guava guava com.baeldung projekt-b 0.0.1-SNAPSHOT 

Nu, når vi kører afhængighed: træ kommando, kan vi se, at det ikke er der længere:

% mvn afhængighed: træ -Dverbose [INFO] --- maven-afhængighed-plugin: 2.8: træ (standard-cli) @ projekt-kollision --- [INFO] com.baeldung: projekt-kollision: jar: 0.0.1 -SNAPSHOT [INFO] \ - com.baeldung: project-b: jar: 0.0.1-SNAPSHOT: compile [INFO] \ - com.google.guava: guava: jar: 29.0-jre: compile

Som et resultat slutter kompileringsfasen uden en fejl, og vi kan bruge klasser og metoder fra version 29,0-jre.

4. Brug af afhængighedLedelse Afsnit

Maven's afhængighedLedelse sektion er en mekanisme til centralisering af afhængighedsinformation. En af dens mest nyttige funktioner er at kontrollere versioner af artefakter, der bruges som transitive afhængigheder.

Med det i tankerne, lad os oprette en afhængighedLedelse konfiguration i vores forælder pom:

   com.google.guava guava 29.0-jre 

Som et resultat vil Maven sørge for at bruge versionen 29,0-jre af com.google.guava artefakt i alle underordnede moduler:

% mvn afhængighed: træ -Dverbose [INFO] --- maven-afhængighed-plugin: 2.8: træ (standard-cli) @ projektkollision --- [INFO] com.baeldung: projektkollision: jar: 0.0.1 -SNAPSHOT [INFO] + - com.baeldung: projekt-a: jar: 0.0.1-SNAPSHOT: kompil [INFO] | \ - com.google.guava: guava: jar: 29.0-jre: kompil (version administreret fra 22.0) [INFO] \ - com.baeldung: projekt-b: jar: 0.0.1-SNAPSHOT: kompilere [INFO] \ - (com.google.guava: guava: jar: 29.0-jre: kompil - version administreret fra 22.0; udeladt til duplikat)

5. Forhindre utilsigtede transitive afhængigheder

Det maven-enforcer-plugin giver mange indbyggede regler, der forenkle styringen af ​​et multimodulprojekt. En af dem forbyder brugen af ​​klasser og metoder fra transitive afhængigheder.

Eksplicit afhængighedserklæring fjerner muligheden for versionskollision af artefakter. Lad os tilføje maven-enforcer-plugin med den regel til vores forældre pom:

 org.apache.maven.plugins maven-enforcer-plugin 3.0.0-M3 håndhæver-forbudte afhængigheder håndhæver 

Som en konsekvens skal vi nu udtrykkeligt erklære com.google.guava artefakt i vores projekt-kollision modul, hvis vi selv vil bruge det. Vi skal enten specificere den version, der skal bruges, eller konfigurere afhængighedLedelse hos forældrene pom.xml. Dette gør vores projekt mere fejlsikkert, men kræver, at vi er mere eksplicitte i vores pom.xml filer.

6. Konklusion

I denne artikel har vi set, hvordan man løser en versionskollision af artefakter i Maven.

Først undersøgte vi et eksempel på en versionskollision i et multimodulprojekt.

Derefter viste vi, hvordan man udelukker transitive afhængigheder i pom.xml. Vi så på, hvordan man styrer afhængighedsversioner med afhængighedLedelse sektion i forældrene pom.xml.

Endelig prøvede vi maven-enforcer-plugin at forbyde brugen af ​​transitive afhængigheder for at tvinge hvert modul til at tage kontrol over sig selv.

Som altid er koden vist i denne artikel tilgængelig på GitHub.