Transitive Maven dependency shows up in dependency:tree but not in lib directory

Question


I am using Maven 3.0.3 to build a large java project. My pom.xml has a parent which depends on spring-context (compile scope) which in turn depends on spring-expression (also in the compile scope). When I create a dependency tree with mvn:dependencyTree everything looks fine, the spring-expression library turns up as a transitive dependency in compile scope. However if I build an effective pom with mvn help:effective-pom the entry for spring-expression is missing. Also if I build the project the lib for spring-expression is not included in the lib directory while the one for spring-context is.

Until recently the library was included in the build, now something seems to have changed in one of the dependencies. However spring-context is still in the compile scope and shows up in the dependency tree, so I don't see why this should have changed the behavior.

Also, updating Maven (which seems to have solved a possibly related problem here) is sadly not an option. I have temporarily fixed the problem by adding spring-expression as a direct rather than transitive dependency to my project but I'd rather not clog up the pom with stuff that should already be there. Any ideas?

Update: Weirder and weirder... While trying to come up with a minimal example I found one - sort of. This is what I came up with:

<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>org.test.project</groupId>
  <artifactId>test-project</artifactId>
  <packaging>war</packaging>
  <version>0.1-SNAPSHOT</version>
  <name>Test Project</name>

  <properties>
    <spring.version>3.2.4.RELEASE</spring.version>
  </properties>

  <dependencies>
    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

It works in that the transitive dependency spring-expression is shown in the output of mvn:dependencyTree:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Test Project 0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ test-project ---
[INFO] org.test.project:test-project:war:0.1-SNAPSHOT
[INFO] \- org.springframework:spring-context:jar:3.2.4.RELEASE:runtime
[INFO]    +- org.springframework:spring-aop:jar:3.2.4.RELEASE:runtime
[INFO]    |  \- aopalliance:aopalliance:jar:1.0:runtime
[INFO]    +- org.springframework:spring-beans:jar:3.2.4.RELEASE:runtime
[INFO]    +- org.springframework:spring-core:jar:3.2.4.RELEASE:runtime
[INFO]    |  \- commons-logging:commons-logging:jar:1.1.1:runtime
[INFO]    \- org.springframework:spring-expression:jar:3.2.4.RELEASE:runtime
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.922s
[INFO] Finished at: Thu Apr 10 16:17:42 CEST 2014
[INFO] Final Memory: 5M/15M
[INFO] ------------------------------------------------------------------------

and not in the effective pom:

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.test.project</groupId>
  <artifactId>test-project</artifactId>
  <version>0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>Test Project</name>
  <distributionManagement>
    <repository>
      <id>internal_repo</id>
      <name>Repository for internal artefacts</name>
      <url>http://internal/url</url>
    </repository>
    <snapshotRepository>
      <id>internal_repo</id>
      <name>Repository for internal artefacts</name>
      <url>http://internal/url</url>
    </snapshotRepository>
  </distributionManagement>
  <properties>
    <downloadJavadocs>true</downloadJavadocs>
    <downloadSources>true</downloadSources>
    <spring.version>3.2.4.RELEASE</spring.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>3.2.4.RELEASE</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <id>central</id>
      <url>http://internal/url</url>
    </repository>
    <repository>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <id>maven3</id>
      <url>http://internal/url</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <id>central</id>
      <url>http://internal/url</url>
    </pluginRepository>
    <pluginRepository>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <id>maven3</id>
      <url>http://internal/url</url>
    </pluginRepository>
  </pluginRepositories>
  <build>
    <sourceDirectory>c:\projects\test-project\src\main\java</sourceDirectory>
    <scriptSourceDirectory>c:\projects\test-project\src\main\scripts</scriptSourceDirectory>
    <testSourceDirectory>c:\projects\test-project\src\test\java</testSourceDirectory>
    <outputDirectory>c:\projects\test-project\target\classes</outputDirectory>
    <testOutputDirectory>c:\projects\test-project\target\test-classes</testOutputDirectory>
    <resources>
      <resource>
        <directory>c:\projects\test-project\src\main\resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>c:\projects\test-project\src\test\resources</directory>
      </testResource>
    </testResources>
    <directory>c:\projects\test-project\target</directory>
    <finalName>test-project-0.1-SNAPSHOT</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.4.1</version>
        <executions>
          <execution>
            <id>default-clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.3.1</version>
        <executions>
          <execution>
            <id>default-install</id>
            <phase>install</phase>
            <goals>
              <goal>install</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
          <execution>
            <id>default-resources</id>
            <phase>process-resources</phase>
            <goals>
              <goal>resources</goal>
            </goals>
          </execution>
          <execution>
            <id>default-testResources</id>
            <phase>process-test-resources</phase>
            <goals>
              <goal>testResources</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.7.2</version>
        <executions>
          <execution>
            <id>default-test</id>
            <phase>test</phase>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <executions>
          <execution>
            <id>default-testCompile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>testCompile</goal>
            </goals>
          </execution>
          <execution>
            <id>default-compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <executions>
          <execution>
            <id>default-war</id>
            <phase>package</phase>
            <goals>
              <goal>war</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>default-deploy</id>
            <phase>deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-site-plugin</artifactId>
        <version>2.0.1</version>
        <executions>
          <execution>
            <id>default-site</id>
            <phase>site</phase>
            <goals>
              <goal>site</goal>
            </goals>
            <configuration>
              <outputDirectory>c:\projects\test-project\target\site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
          <execution>
            <id>default-deploy</id>
            <phase>site-deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
            <configuration>
              <outputDirectory>c:\projects\test-project\target\site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
        </executions>
        <configuration>
          <outputDirectory>c:\projects\test-project\target\site</outputDirectory>
          <reportPlugins>
            <reportPlugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-project-info-reports-plugin</artifactId>
            </reportPlugin>
          </reportPlugins>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <outputDirectory>c:\projects\test-project\target\site</outputDirectory>
  </reporting>
</project>

However when I build the project the lib directory does include spring-expression in this example. How can this be?



Answer


I am running with maven 3.1.1 and the dependency spring-expressionis correctly added to WEB-INF/lib. The effective pom does not contain spring-expression, but that is normal as the effective pom does not resolve transitive dependencies.

The effective pom is just a merged xml file with the current pom plus all it's parents merged together. The maven dependency resolution mechanism is applied only after the effective pom is built.

This is the reason why the effective pom only contains the spring-context dependency, because that was the only thing specified in the pom.xml. If there would be parent dependencies in a parent pom they would show up in the effective pom too.

This is my output of mvn dependency:tree:

INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ test-project ---
[INFO] org.test.project:test-project:war:0.1-SNAPSHOT
[INFO] \- org.springframework:spring-context:jar:3.2.4.RELEASE:runtime
[INFO]    +- org.springframework:spring-aop:jar:3.2.4.RELEASE:runtime
[INFO]    |  \- aopalliance:aopalliance:jar:1.0:runtime
[INFO]    +- org.springframework:spring-beans:jar:3.2.4.RELEASE:runtime
[INFO]    +- org.springframework:spring-core:jar:3.2.4.RELEASE:runtime
[INFO]    |  \- commons-logging:commons-logging:jar:1.1.1:runtime
[INFO]    \- org.springframework:spring-expression:jar:3.2.4.RELEASE:runtime

and these is my WEB-INF/lib contents:

aopalliance-1.0.jar
commons-logging-1.1.1.jar
spring-aop-3.2.4.RELEASE.jar
spring-beans-3.2.4.RELEASE.jar
spring-context-3.2.4.RELEASE.jar
spring-core-3.2.4.RELEASE.jar
spring-expression-3.2.4.RELEASE.jar

So the issue seems to be some misunderstanding of the effective pom feature together with a missing dependency spring-expression in WEB-INF lib due to a maven bug: this problem is solvable via version upgrade or hardcoding dependency on the pom as workaround as you found out.