Gradle still tries to figure out version of dependency even if it's excluded

In my project I have dependency on org.jboss.seam.validation:seam-validation-api:3.1.0.Final. It has dependency on javax.enterprise:cdi-api, but without version, so gradle fails to resolve it. It shouldn’t be a big deal, I can exclude javax.enterprise:cdi-api.

The problem is, even if excluded, gradle still tries to figure out version number, and fails the whole build.

Error message:

Could not resolve all dependencies for configuration ‘:compile’.

Could not resolve org.jboss.seam.validation:seam-validation-api:3.1.0.Final.

Required by:

com.smspl.mc5:mc5-web-ui:1.0.0-SNAPSHOT

Could not parse POM /Users/amorfis/.m2/repository/org/jboss/seam/validation/seam-validation-api/3.1.0.Final/seam-validation-api-3.1.0.Final.pom

Unable to resolve version for dependency ‘javax.enterprise:cdi-api:jar’

Could not parse POM https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/seam/validation/seam-validation-api/3.1.0.Final/seam-validation-api-3.1.0.Final.pom

Unable to resolve version for dependency ‘javax.enterprise:cdi-api:jar’

Please include all relevant parts of the build script (wrapped in HTML code tags) and the output of ‘gradle -v’.

The build script is quite simple. Relevant part:

dependencies {
    compile(group: 'org.jboss.seam.validation', name: 'seam-validation-api', version: '3.1.0.Final') {
        exclude(module: 'cdi-api')
    }
}

gradle -v:

------------------------------------------------------------
Gradle 1.10
------------------------------------------------------------
  Build time:
 2013-12-17 09:28:15 UTC
Build number: none
Revision:
   36ced393628875ff15575fa03d16c1349ffe8bb6
  Groovy:
     1.8.6
Ant:
        Apache Ant(TM) version 1.9.2 compiled on July 8 2013
Ivy:
        2.2.0
JVM:
        1.7.0_25 (Oracle Corporation 23.25-b01)
OS:
         Mac OS X 10.9.1 x86_64

I’m the author of this question on SO: http://stackoverflow.com/questions/20935891/gradle-cannot-resolve-dependency

Could you please also provide us with the repositories you are using?

Sure:

repositories {
    mavenLocal()
    maven { url "http://repository.jboss.org/" }
    maven { url "https://nexus.softwaremill.com/content/groups/smlcommon-repos/" }
    mavenCentral()
}

This specific archives are in jboss repo.

Thanks, I can reproduce the issue. The exclude of the module doesn’t work at the moment as the version of the dependency cannot be resolving when parsing the POM (which happens earlier than the exclude). I think we will need to be less strict in this case (especially because the scope of “cdi-api” is “provided”).

My first question would be whether this is a valid Maven POM, and if so, why.

I think it’s debatable. On the one hand the version cannot be resolved which means that the dependency would generally not be resolvable. On the other hand the POM at least is treated gracefully when resolving it through Maven. My guess is that Maven also has a look at the scope. If the scope is not “compile” or “runtime”, then it doesn’t care about the missing version.

According to http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html, ‘provided’ dependencies go on the same module’s test class path. If that’s true, they need a version. Are we sure that in the concrete case, the version isn’t hidden somewhere?

I found a defined version of that dependency deeply nested in imported POMs:

https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/seam/validation/seam-validation-api/3.1.0.Final/seam-validation-api-3.1.0.Final.pom -> (POM parent) https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/seam/validation/seam-validation-parent/3.1.0.Final/seam-validation-parent-3.1.0.Final.pom -> (POM import) https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/seam/seam-bom/3.1.0.Final/seam-bom-3.1.0.Final.pom -> (POM import) https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/spec/jboss-javaee-6.0/2.0.0.Final/jboss-javaee-6.0-2.0.0.Final.pom -> (POM import) https://nexus.softwaremill.com/content/groups/smlcommon-repos/org/jboss/spec/jboss-javaee6-specs-bom/2.0.0.Final/jboss-javaee6-specs-bom-2.0.0.Final.pom

Do you think that should work?

Good question, but it looks reasonable. (I wish there was a spec for this stuff.) Do we currently support ‘import’ for less fancy cases?

We do support the POM import scope. I guess we’d need to set up a more complex test case to see what is going wrong there.

Shouldn’t it first exclude, and then try to resolve version? Seems to make most sense for me.

I had a deeper look at this issue. In one of the POMs, seam-bom-3.1.0-Final.pom, that is part of the POM import chain, we see the following:

<dependencyManagement>
    <dependencies>
        <!--
import the individual Java EE 6 API spec versions
-->
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>${jboss.javaee.version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
        <!--
make Java EE 6 API available as stack artifact
-->
        <!--
yes, we really need this one too!
-->
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>${jboss.javaee.version}</version>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
        ...
    </dependencies>
</dependencyManagement>

The imported POM is declared with scope ‘import’, later is defined with scope ‘provided’. When we parse the POM and identify multiple dependencies with the same ‘groupId’, ‘artifactId’ and ‘version’ we pick the last. As the scope of the last definition is ‘provided’, we do not import the POM. That’s why the property and the relevant ‘dependencyManagement’ declaration cannot be resolved. I am not sure why the dependency was declared twice with different scopes.

I can see that rationale. It’s simply not how it works at the moment. That would certainly be a deeper change.

Concerning your last sentence I’ll try to explain:

The two imports have different meanings: The dependency-statement with scope ‘import’ imports all the definitions for the dependencies listed in the project/dependencyManagement/dependencies tag. The other one with scope ‘provided’ adds all the dependencies from the project/dependencies, like minimal/recommended dependencies. So you can define all the dependencies with the versions in dependencyManagement but you have not to add all in every case.

Hope it helps.

Btw. I’m looking forward to an implementation of this functionality in gradle. :slight_smile:

Would you mind trying this out with 1.12-rc-1?