Dependency resolution, classifiers and Maven interoperability

Hi Gradle experts,

We have a number of Maven and Gradle projects here and I thought it is a good idea to use mavenLocal() to consume artifacts generated by Maven (especially those under development). Now I’m confronted with an issue regarding classifier dependency resolution within Gradle.

We’ve got a library project (let’s call it sample-library) that produces two artifacts. The first one is the main artifact and the second one contains only the projects resources (src/main/resources) thus has classifier resources. Assume the local Maven repository is empty and a Maven projects demands com.acme:sample-library:0.0.10-SNAPSHOT. ~/.m2/repository now looks like this:

\---com/acme/sample-library
    \---0.0.10-SNAPSHOT
            maven-metadata-nexus.xml
            maven-metadata-nexus.xml.sha1
            resolver-status.properties
            sample-library-0.0.10-20151023.123304-1.jar
            sample-library-0.0.10-20151023.123304-1.jar.sha1
            sample-library-0.0.10-20151023.123304-1.pom
            sample-library-0.0.10-20151023.123304-1.pom.sha1
            sample-library-0.0.10-SNAPSHOT.jar
            sample-library-0.0.10-SNAPSHOT.pom
            _remote.repositories

Afterwards in our Gradle project, we consume only the resources artifact com.acme:sample-library:0.0.10-SNAPSHOT:resources. When building the project I got the following error message:

:compileJava

FAILURE: Build failed with an exception.

* What went wrong:
Could not resolve all dependencies for configuration ':compile'.
> Could not find sample-library-resources.jar (com.acme:sample-library:0.0.10-SNAPSHOT).
  Searched in the following locations:
      file:/C:/Users/user.home/.m2/repository/com/acme/sample-library/0.0.10-SNAPSHOT/sample-library-0.0.10-SNAPSHOT-resources.jar

The build.gradle contains repository configuration for our corporate Nexus instance:

repositories {
    mavenLocal()

    maven {
        url "$nexus/groups/company"

        credentials {
            username nexusUsername
            password nexusPassword
        }
    }

    maven {
        url "$nexus/groups/public"

        credentials {
            username nexusUsername
            password nexusPassword
        }
    }
}

As Nexus contains the required (classifier) artifact, I expect Gradle to download the artifact if it cannot be found in mavenLocal().

Is this a bug?

Your M2 local cache directory listing doesn’t look like it actually contains an artifact with the resources classifier. Is this missing or just not shown?

Thanks for the interest! The artifact with the resources classifier is indeed missing in the M2 local cache directory. But as the initial Maven project build has only a dependency to the main artifact (without classifier) I think that’s reasonable behavior.

Is it worth to file an issue?

This issue is already reported as GRADLE-3178.

Thanks for pointing this out daz! Is this scheduled to be fixed in a future release?

No, this fix is not currently scheduled.

If we find a repository that has metadata for a module, we assume that it contains all of the artifacts for that module. Unfortunately this is different from Maven. The best workaround is usually to remove mavenLocal from your repository list, or at the very least put it last.

This isn’t a very good solution because the local repo (.m2) typically isn’t a complete repo, i.e. you only have a subset of what’s contained in external repos. In the case of classifiers, there could be N classified artifacts for any given artifact and NO way for the caller to know how to download all those since there’s no listing mechanism in maven to identify all the classified artifacts.

A good example of this is saxon:

https://repo1.maven.org/maven2/net/sourceforge/saxon/saxon/9.1.0.8/

How is the local repo supposed to handle that?