Resolving maven dependencies from an ivy repository includes all configurations of the ivy module


(rainer.frey) #1

I noticed following problem when using maven and ivy repositories. My motivation for doing that is: * our main dependency repository is an internal ivy repository (manually maintained, carefully defined dependency configurations) * a few libraries are patched by us, and deployed into our internal Nexus (as that already exists for other, maven-oriented projects)

Now the problem is: * direct project dependency is a patched version in the Nexus maven repo * transitive dependencies of that are original versions in the ivy repository * when gradle resolves these transitive dependencies, it references all configurations of the ivy modules (including the one I use for sources)

I’m aware that maven has no support for dependency configurations like ivy does, but I would have expected the default configuration to be referenced, not all.

output

$ gradle dependencies
compile - Classpath for compiling the main sources.
+--- com.inxmail:jakarta-slide-webdavlib:2.2pre1-inxfix [default]
 # <-- in Nexus maven repo
|
  +--- org.apache.commons:commons-httpclient:3.1 [default]
  # <-- in ivy repo, has only default configuration, so "works by accident"
|
  |
  \--- org.apache.commons:commons-codec:1.4 [default] (*)
|
  \--- org.jdom:jdom:1.1.2 [default,source,javadoc]
    # <-- source and javadoc configurations are unwanted here

build.gradle dependency declaration

dependencies {
// ...
 compile "com.inxmail:jakarta-slide-webdavlib:2.2pre1-inxfix"
}

jakarta-slide-webdavlib pom.xml

<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.inxmail</groupId>
  <artifactId>jakarta-slide-webdavlib</artifactId>
  <version>2.2pre1-inxfix-SNAPSHOT</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.jdom</groupId>
      <artifactId>jdom</artifactId>
      <version>1.1.2</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

jdom ivy.xml

<ivy-module xmlns:m="http://ant.apache.org/ivy/maven">
    <configurations>
        <conf name="default"/>
        <conf name="source"/>
        <conf name="javadoc"/>
    </configurations>
      <publications>
        <artifact conf="default"/>
        <artifact name="jdom-source" type="source" ext="jar" m:classifier="sources" conf="source"/>
        <artifact name="jdom-javadoc" type="javadoc" ext="jar" m:classifier="javadoc" conf="javadoc"/>
    </publications>
</ivy-module>

Resolving transitive ivy modules from maven dependency
#2

What you’re seeing is the result of how Gradle maps Maven POM dependency elements to it’s internal representation of dependencies, which is heavily based on ivy.

In you example above, the jdom dependency in ‘compile’ scope gets mapped as if it were an ivy dependency declaration like:

<dependency
         org="jdom" name="jdom" rev="1.1.2"
         conf="compile->compile(*),master(*);runtime->runtime(*)"/>

When resolving the compile dependencies of module, Gradle will attempt to resolve the ‘default’ configuration, which for a POM module includes the following ivy configurations: default, master, compile, runtime. (The runtime configuration should not be resolved, but it is currently.) Since the POM dependency maps ‘compile -> compile(*)’, it will use your ivy module’s ‘compile’ configuration if defined, or use all configurations if not. Same goes for ‘master’ and ‘runtime’ configurations.

So to get your ivy modules to play nicely with maven pom-based modules, you’ll need to declare them with all 3 configurations: master, compile and runtime. If you miss any of these, then Gradle will use the fallback ‘*’, and all configurations will be used.

Here is an example:

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
   <info organisation="org.jdom" module="jdom" revision="1.1" status="integration" />
    <configurations>
        <conf name="master"/>
        <conf name="compile" extends="master"/>
        <conf name="runtime" extends="compile"/>
        <conf name="default" extends="compile,runtime"/>
        <conf name="source"/>
        <conf name="javadoc"/>
    </configurations>
    <publications>
        <artifact conf="master"/>
        <artifact name="jdom" type="source" ext="jar" m:classifier="sources" conf="source"/>
    </publications>
</ivy-module>

We are working on continued improvements to dependency resolution, which will include a better model for mapping between Maven and Ivy-based modules. For now, I hope the above workaround will suite.


(rainer.frey) #3

I see, thanks for explaining! JFTR I still find mapping to the “default” configuration more intuitive.

One nitpick though: I don’t see this mapping documented anywhere in the user guide or DSL reference. I’d never found that by myself.


#4

Indeed: I spent quite some time working it out myself! We’ll look at adding some documentation with our upcoming improvements: until then this forum post will suffice, I suppose.