Maven
dependency
puzzlers

Every question is the same:

Which jars end up
in the production classpath
of myproject?

Count your points

  • Your answer is ...
    • correct: +3 points
    • I don't know: +1 point
    • wrong: +0 points
  • Most points:
    Chance to win
    1 bottle of beer

Which jars on the classpath?

After running

$ mvn assembly:single

on myproject's pom.xml
with assembly configuration

<assembly>

  ...

  <dependencySets>
    <dependencySet>
      <outputDirectory/>
    </dependencySet>
  </dependencySets>

</assembly>

Environment




Question 1

Different groupId

<project>
  <artifactId>myproject</artifactId>
  ...
  <dependencies>
    <dependency>
      <groupId>javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.12.1.GA</version>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.16.1-GA</version>
    </dependency>
  </dependencies>
</project>

Different groupId

Which jars on the classpath?

  • javassist-3.12.1.GA.jar
  • javassist-3.16.1-GA.jar
  • javassist-3.12.1.GA.jar
    + javassist-3.16.1-GA.jar
  • neither
  • Maven error
  • I don't know

Answer different groupId

Which jars on the classpath?

  • javassist-3.12.1.GA.jar
  • javassist-3.16.1-GA.jar
  • javassist-3.12.1.GA.jar
    + javassist-3.16.1-GA.jar
  • neither
  • Maven error
  • I don't know

Workaround different groupId's

Ban outdated GAVs (groupId - artifactId)

Solution different groupId

meanwhile in Maven Central ...

groupId's of Sun's JAXB implementation

Don't redistribute other project's artifacts under your groupId.




Question 2

Dependency inheritance

<project>
  <artifactId>myparent</artifactId>...
  <dependencyManagement><dependencies>
    <dependency>...
      <artifactId>commons-lang</artifactId>
      <version>2.4</version>
    </dependency>
  </dependencies></dependencyManagement>
  <dependencies>
    <dependency>...
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
  </dependencies>
</project>
<project>
  <parent>...
    <artifactId>myparent</artifactId>...
  </parent>
  <artifactId>myproject</artifactId>...
  <dependencies>
    <dependency>...
      <artifactId>commons-lang</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>...
      <artifactId>commons-io</artifactId>
      <version>2.3</version>
    </dependency>
  </dependencies>
</project>

Dependency inheritance

Which jars on the classpath?

  • commons-lang-2.3.jar (my dep)
    + commons-io-2.3.jar (my dep)
  • commons-lang-2.3.jar (my dep)
    + commons-io-2.4.jar (parent dep)
  • commons-lang-2.4.jar (parent man)
    + commons-io-2.3.jar (my dep)
  • commons-lang-2.4.jar (parent man)
    + commons-io-2.4.jar (parent dep)
  • Maven error
  • I don't know

Answer dependency inheritance

Which jars on the classpath?

  • commons-lang-2.3.jar (my dep)
    + commons-io-2.3.jar (my dep)
  • commons-lang-2.3.jar (my dep)
    + commons-io-2.4.jar (parent dep)
  • commons-lang-2.4.jar (parent man)
    + commons-io-2.3.jar (my dep)
  • commons-lang-2.4.jar (parent man)
    + commons-io-2.4.jar (parent dep)
  • Maven error
  • I don't know

Solution dependency inheritance

<project>
  <artifactId>myparent</artifactId>...
  <dependencyManagement><dependencies>
    <dependency>...
      <artifactId>commons-lang</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>...
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
  </dependencies></dependencyManagement>
</project>
<project>
  <parent>...
    <artifactId>myparent</artifactId>...
  </parent>
  <artifactId>myproject</artifactId>...
  <dependencies>
    <dependency>...
      <artifactId>commons-lang</artifactId>
      <!-- No version specified -->
    </dependency>
    <dependency>...
      <artifactId>commons-io</artifactId>
      <!-- No version specified -->
    </dependency>
  </dependencies>
</project>




Question 3

Conflicting nephew

<project>
  <artifactId>a</artifactId>...
  <dependencies>
    <dependency>...
      <artifactId>slf4j-api</artifactId>
      <version>1.7.0</version>
    </dependency>
  </dependencies>
</project>
<project>
  <artifactId>myproject</artifactId>...
  <dependencies>
    <dependency>...
      <artifactId>a</artifactId>...
    </dependency>
    <dependency>...
      <artifactId>slf4j-api</artifactId>
      <version>1.5.0</version>
    </dependency>
  </dependencies>
</project>

Conflicting nephew

Which jars on the classpath?

  • slf4j-api-1.5.0.jar
  • slf4j-api-1.7.0.jar
  • slf4j-api-1.5.0.jar
    + slf4j-api-1.7.0.jar
  • neither
  • Maven error
  • I don't know

Answer conflicting nephew

Which jars on the classpath?

  • slf4j-api-1.5.0.jar
  • slf4j-api-1.7.0.jar
  • slf4j-api-1.5.0.jar
    + slf4j-api-1.7.0.jar
  • neither
  • Maven error
  • I don't know

Workaround: Fail fast with enforcer

Enforce that every (transitive) dependency is resolved to its specified version or higher.

<plugin>
  <artifactId>maven-enforcer-plugin</artifactId>
  <executions>
    <execution>
      <goals><goal>enforce</goal></goals>
      <configuration>
        <rules>
          <requireUpperBoundDeps/>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>
Failed while enforcing RequireUpperBoundDeps. The error(s) are [
Require upper bound dependencies error for org.slf4j:slf4j-api:1.5.0 paths to dependency are:
+-...:myproject:1.0.0
  +-org.slf4j:slf4j-api:1.5.0
and
+-...:myproject:1.0.0
  +-...:a:1.0.0
    +-org.slf4j:slf4j-api:1.7.0
]




Question 4

Conflicting cousins

<project>...<artifactId>a</>...
  <dependencies>
    <dependency>...
      <artifactId>drools-core</artifactId>
      <version>5.2.0.CR1</version>
    </dependency>
  </dependencies>
</project>
<project>...<artifactId>b</>...
  <dependencies>
    <dependency>...
      <artifactId>drools-core</artifactId>
      <version>5.2.0.M2</version>
    </dependency>
  </dependencies>
</project>
<project>...<artifactId>c</>...
  <dependencies>
    <dependency>...
      <artifactId>drools-core</artifactId>
      <version>5.2.0.Final</version>
    </dependency>
  </dependencies>
</project>
<project>...<artifactId>myproject</>...
  <dependencies>
    <dependency>...<artifactId>a</>...</>
    <dependency>...<artifactId>b</>...</>
    <dependency>...<artifactId>c</>...</>
  </dependencies>
</project>

Conflicting cousins

Which jars on the classpath?

  • drools-core-5.2.0.CR1.jar
  • drools-core-5.2.0.M2.jar
  • drools-core-5.2.0.Final.jar
  • drools-core-5.2.0.CR1.jar
    + drools-core-5.2.0.M2.jar
    + drools-core-5.2.0.Final.jar
  • Maven error
  • I don't know

Answer conflicting cousins

Which jars on the classpath?

  • drools-core-5.2.0.CR1.jar
  • drools-core-5.2.0.M2.jar
  • drools-core-5.2.0.Final.jar
  • drools-core-5.2.0.CR1.jar
    + drools-core-5.2.0.M2.jar
    + drools-core-5.2.0.Final.jar
  • Maven error
  • I don't know

Later drools releases (5.3, 5.4, 5.5, ...)
no longer use M in version numbering.

Lexicographic version numbering

Workaround conflicting cousins

Conflict resolution in Maven ...

Conflict resolution in practice ...

Common sense solution:
Retain the highest version (using lexicographic comparison)

Maven 3.1 or Tesla could fix this with pluggable conflict resolution?




Question 5

Child with dependencyManagement

<project>...<artifactId>a</>...
  <dependencies>
    <dependency>...
      <artifactId>jbpm-flow</artifactId>
      <version>5.1.0.Final</version>
    </dependency>
  </dependencies>
</project>
<project>...<artifactId>yourparent</>...
  <dependencyManagement><dependencies>
    <dependency>...
      <artifactId>jbpm-flow</artifactId>
      <version>5.3.0.Final</version>
    </dependency>
  </dependencies></dependencyManagement>
</project>
<project>...<artifactId>yourproject</>...
  <parent>...<artifactId>yourparent</>...</parent>
  <dependencies>
    <dependency>...
      <artifactId>a</artifactId>
    </dependency>
  </dependencies>
</project>
<project>...<artifactId>myproject</>...
  <dependencies>
    <dependency>...
      <artifactId>yourproject</artifactId>...
    </dependency>
  </dependencies>
</project>

Child with dependencyManagement

Which jars on the classpath?

  • jbpm-flow-5.1.0.Final.jar
  • jbpm-flow-5.3.0.Final.jar
  • Maven error
  • I don't know

Child with dependencyManagement

Which jars on the classpath?

  • jbpm-flow-5.1.0.Final.jar
  • jbpm-flow-5.3.0.Final.jar
  • Maven error
  • I don't know

myproject versus yourproject

myproject depends on yourproject
but ends up with a different jbpm-flow version




Question 6

Fat jars

<project>
  <artifactId>myproject</artifactId>
  ...
  <dependencies>
    <dependency>
      <-- Depends on:
          slf4j-api 1.6.1
          ... -->
      <groupId>org.jboss.weld.se</groupId>
      <artifactId>weld-se-core</artifactId>
      <version>1.1.8.Final</version>
    </dependency>
    <dependency>
      <-- Duplicates:
          weld-se-core 1.1.4.Final
          slf4j-api 1.5.10
          ... -->
      <groupId>org.jboss.weld.se</groupId>
      <artifactId>weld-se</artifactId>
      <version>1.1.4.Final</version>
    </dependency>
  </dependencies>
</project>

Fat jars

Which jars on the classpath?

  • weld-se-core-1.1.8.Final.jar
    + slf4j-api-1.6.1.jar
  • weld-se-1.1.4.Final.jar
  • weld-se-core-1.1.8.Final.jar
    + slf4j-api-1.6.1.jar
    + weld-se-1.1.4.Final.jar
  • Maven error
  • I don't know

Answer fat jars

Which jars on the classpath?

  • weld-se-core-1.1.8.Final.jar
    + slf4j-api-1.6.1.jar
  • weld-se-1.1.4.Final.jar
  • weld-se-core-1.1.8.Final.jar
    + slf4j-api-1.6.1.jar
    + weld-se-1.1.4.Final.jar
  • Maven error
  • I don't know

Solution fat jars

Don't depend on fat jars.

<project>
  <artifactId>myproject</artifactId>
  ...
  <dependencies>
    <dependency>
      <groupId>org.jboss.weld.se</groupId>
      <-- <artifactId>weld-se</artifactId> is evil -->
      <artifactId>weld-se-core</artifactId>
      <version>1.1.8.Final</version>
    </dependency>
  </dependencies>
</project>

Shaded fat jars

  • Shading
    • Prefixes all classes
      with namespace
  • Bad solution
    • Does not fix problem
    • Extra problems
  • Don't use shaded jars

And the winner is ...

Q & A