Dependency substutition - correct module syntax when substitute a local jar with something else?


(lu.shunshun) #1

We have a multiproject build and all the libraries are on the local file systemt (repository is faltDir).

One of the project needs to replace a jar of the runtime dependency with a project dependency. Here’s what I mean:

configurations {
    runtime {
        resolutionStrategy.dependencySubstitution {
           // replace OCAP11 with a mock at runtime
           substitute module("OCAP11") with project(':OCAPFakes')
        }
    }
}

“OCAP11” is basically a local jar file (“ocap11.jar”) lives under the “lib” folder which is the root of our repository. The issue I’m having is that this module("OCAP11") syntax does not work and Gradle complains with the following message:

Cannot convert the provided notation to an object of type ComponentSelector: OCAP11.
  The following types/formats are supported:
    - Instances of ComponentSelector.
    - String describing the module in 'group:name' format, for example 'org.gradle:gradle-core'..
    - String describing the selector in 'group:name:version' format, for example 'org.gradle:gradle-core:1.+'..

The problem is that this jar file doesn’t have a group name and version number so I have to leave this two parts empty. I’ve triedmodule(":OCAP11:"), module(":OCAP11") and module("OCAP:") but none of them works.

Any ideas how should it be done?


(lu.shunshun) #2

Basically, my question is "What is the correct syntax to reference a local jar file living in the root of the repository (no group and no version number) when calling dependencySubstitution.module method"?


(Lance Java) #3

How are you declaring your dependencies? I think that the dependencySubstitution can only substiture ModuleDependency and ProjectDependency instances.

If you are declaring as

dependencies {
   compile files('lib/OCAP11.jar')
}

Then the dependency will be an instance of FileCollectionDependency (I think)

As a workaround, you could store the file at
libs/OCAP11/1.0/OCAP11-1.0.jar

And then declare:

maven {
   url uri('libs')
}
dependencies {
   compile 'OCAP11:OCAP11:1.0'
}

Then you should be able to substitute it as a normal module


(Lance Java) #4

Alternatively, you might be able to use resolutionStrategy.eachDependency


(lu.shunshun) #5

Thanks for the reply. We are not delcaring dependencies as file collections directly in the build script. Here’s how we do it:

repositories {
    flatDir {
        dirs "lib"
}

“OCAP11.jar” lives in the root of the “lib” folder along with other libraries (some of them are living in subfolders, e.g. guava is in lib/guava/guava-12.0.jar")

When declaring dependencies, I just need to do this:

dependencies {
    compile ":OCAP11:"
    compile "guava:guava:12.0"
}

Note, group and version are left empty and everything works fine. This is why I thought I can use the same syntax when doing dependency substitution but apparently not working.

configurations {
    runtime {
        resolutionStrategy.dependencySubstitution {
           // replace OCAP11 with a mock at runtime
           substitute module(":OCAP11:") with project(':OCAPFakes')
        }
    }
}

Is it necessary to put the jar file in a folder in order to give it a group name? or is this something Gradle can be more flexible about?


(Lance Java) #6

Looks like DefaultModuleComponentSelector requires group/name/version. You could try creating your own ModuleComponentSelector implementation which only matches name in matchesStrictly(…)

Eg:

class FlatDirModuleComponentSelector implements ModuleComponentSelector { 
   String name;

   FlatDirModuleComponentSelector(String name) { 
      this.name = name;
   } 

   boolean matchesStrictly(ComponentIdentifier id) {
      if (id instanceof ModuleComponentIdentifier) {
         ModuleComponentIdentifier mci = (ModuleComponentIdentifier) id
         return mci.group==null && mci.version == null && this.name.equals(mci.name)
      }
      return false;
   }

   // TODO other methods to satisfy interface
   // TODO equals() and hashCode()
}

configurations {
   runtime {
      resolutionStrategy.dependencySubstitution {
         def selector = new FlatDirModuleComponentSelector("OCAP11")
         substitute selector with project(':OCAPFakes')
      }
   }
}