Maven en dependencies

 
08 februari 2008

Zoals ik al eerder had beloofd ga ik een stukje schrijven over Maven en dependencies.

Iets wat ik de vorige niet vertelde is dat Maven bij installatie maar 1.7 MB groot is. Op het moment dat je voor het eerst een commando uitvoert als mvn compile zal Maven deze plugin ophalen van internet.
Als je in je POM aangeeft een afhankelijk te zijn van een library dan zal Maven deze volgens hetzelfde principe ophalen van internet en deze in je lokale repository neer zetten.

Scoping
Maven kent ook iets als scoping. Je dependency die je declareert in je POM heeft een scope aanduiding om aan te geven of de library gebruikt wordt tijdens het compileren, testen of tijdens het uitvoeren van je applicatie.

<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <groupId>nl.sogyo.test</groupId>
   <artifactId>some-app</artifactId>
   <version>1.0-SNAPSHOT</version>

   <dependencies>
      <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.13</version>
         <scope>compile</scope>
      </dependency>
   </dependencies>
</project>

In het bovenstaande voorbeeld zal Maven log4j versie 1.2.13 ophalen van internet en deze library tijdens het compileren op de classpath zetten. Zo is er ook nog een een speciale scope genaamd ‘provided’. Als je een applicatie bouwt die in een container komt te draaien (bijvoorbeeld JBoss) dan zal je bijvoorbeeld voor servlets deze scope moeten aangeven. Als je dat niet doet voor library die reeds in de container aanwezig zijn dan zal de container mogelijk de applicatie niet accepteren of de applicatie geeft foutmelding en zal niet werken.

Expliciete en impliciete dependencies
In het voorbeeld van net gaven wij een dependency op. Dit is expliciet. Hierin hebben we ook heel expliciet de versie aangegeven. Maven kent echter ook nog de impliciete dependencies. Dit worden ook wel de transitive dependencies genoemd.
Stel: we gaan een web applicatie gebruiken en maken gebruik van Spring Web MVC en maken dus gebruik van de volgende dependency:

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>2.0.7</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

Wat gebeurt er dan? De volgende dependencies komen automatisch ook mee (groupId:artifactId:versie):

  1. org.springframework:spring-beans:2.0.7
  2. org.springframework:spring-context:2.0.7
  3. org.springframework:spring-core:2.0.7
  4. org.springframework:spring-support:2.0.7
  5. org.springframework:spring-web:2.0.7
  6. com.lowagie:itext:1.4.8
  7. commons-attributes:commons-attributes-api:2.2
  8. commons-attributes:commons-attributes-compiler:2.2
  9. commons-logging:commons-logging:1.1
  10. freemarker:freemarker:2.3.10
  11. jasperreports:jasperreports:1.3.4
  12. javax.servlet:jsp-api:2.0
  13. javax.servlet:jstl:1.1.0
  14. javax.servlet:servlet-api:2.4
  15. jexcelapi:jxl:2.5.7
  16. poi:poi:2.5.1
  17. struts:struts:1.2.9
  18. velocity-tools:velocity-tools-generic:1.3
  19. velocity-tools:velocity-tools-view:1.3
  20. velocity:velocity:1.5

Zoals je ziet krijg je een hoop ‘cadeau’. Het probleem is echter dat je dit wellicht helemaal niet wil je applicatie kan misschien sommige dependencies wel missen.

Analyse
Er is een plugin beschikbaar om te analyseren wat voor dependencies er voor je project zijn. De plugin heet: ‘dependency‘.
Zo kan je een lijst met alle dependencies zien met het volgende commando:

mvn dependency:list

Dit zal ongeveer het volgende tonen op het scherm:

...
[INFO] ------------------------------------------------------------------------
[INFO] Building Test
[INFO]    task-segment: [dependency:list]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:list]
[INFO] 
[INFO] The following files have been resolved:
[INFO]    org.springframework:spring-beans:2.0.7
[INFO]    org.springframework:spring-context:2.0.7
[INFO]    org.springframework:spring-core:2.0.7
[INFO]    org.springframework:spring-support:2.0.7
[INFO]    org.springframework:spring-web:2.0.7
[INFO]    com.lowagie:itext:1.4.8
[INFO]    commons-attributes:commons-attributes-api:2.2
[INFO]    commons-attributes:commons-attributes-compiler:2.2
[INFO]    commons-logging:commons-logging:1.1
[INFO]    freemarker:freemarker:2.3.10
[INFO]    jasperreports:jasperreports:1.3.4
[INFO]    javax.servlet:jsp-api:2.0
[INFO]    javax.servlet:jstl:1.1.0
[INFO]    javax.servlet:servlet-api:2.4
[INFO]    jexcelapi:jxl:2.5.7
[INFO]    poi:poi:2.5.1
[INFO]    struts:struts:1.2.9
[INFO]    velocity-tools:velocity-tools-generic:1.3
[INFO]    velocity-tools:velocity-tools-view:1.3
[INFO]    velocity:velocity:1.5
...

Maar nu? We gaan er van uit dat we in deze lijst twee dependencies hebben die problemen geven: ‘poi’ en ‘servlet-api’. We willen poi helemaal niet en servlet-api is te oud: we willen 2.5. Eerst gaan we poi er maar eens uit slopen.
Dit doen we door de dependency aan te passen. We moeten poi uitsluiten.

...
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>2.0.7</version>
    <scope>compile</scope>
    <exclusions>
      <exclusion>
        <groupId>poi</groupId>
        <artifactId>poi</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
</dependencies>
...

Hiermee hebben we tegen Maven gezegd dat we poi niet mee willen krijgen met deze library.

Versie beheer
Om het servlet-api probleem aan te pakken gaan we wat aan versiebeheer doen. We gaan gebruik maken van <dependencyManagement>.
Door deze sectie toe te voegen aan Maven kunnen we de versies van alle dependencies regelen. Dit houd in: alle expliciete maar ook impliciete versies. Dan komt het er zo uit te zien:

...
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>2.0.7</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <scope>compile</scope>
    <exclusions>
      <exclusion>
        <groupId>poi</groupId>
        <artifactId>poi</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
</dependencies>
...

Versies op plugins
Zo is het versie beheer op plugins ook te regelen door gebruik te maken van <pluginManagement>. Als je binnen je project er echt zeker van wil zijn dat iedereen op dezelfde manier bouwt dan is dit de beste oplossing.

Tot slot wil ik nog een tip geven: als je zoekt naar een open source library dan is de kans al groot dat iemand deze al in de central repository van Maven heeft gezet. Zoek deze dan op mvnrepository.com.

Ik hoop dat stukje een lichtje doet branden bij mensen en dat er nog meer mensen gebruik zullen maken van Maven.


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development

Tags: , , ,


Reactie

  • Thomas Zeeman schreef:

    Zelf gebruik ik nog zowel maven als ant en ik merk dat ik soms in maven dingen mis die ik in ant heel simpel kan doen en omgekeerd.

    Twee dingen die ik zelf erg handig vond zijn iig de M2Eclipse plugin en ivy. M2Eclipse is een maven plugin voor Eclipse waarmee je kunt zoeken in alle repositories die je gebruikt en zie je ook welke dependencies er indirect al in gebruik zijn.
    Ivy is een plugin voor ant en levert dependecymanagement vergelijkbaar aan wat maven ook doet. Ivy maakt daarbij gebruik van o.a. de maven repositories.

    Geplaatst op 17 februari 2008 om 10:05 Permalink