Transforming parts of an ExternalModuleDependency tree

I would like to do a transformation on an object declared as a dependency, without messing with the properties of dependency resolution. For example, instead of:

dependencies {
  compile ''

I would like:

dependencies {
  compile transformed('', ...)

where the transform function is similar to a jarjar/shade/etc. I want to mutate and/or merge some of the artifacts in that tree, but not others, while interfering as little as possible with the resolution strategy for unmutated artifacts.


  1. I want my transformer to operate AFTER dependency resolution, so that if an untransformed version of some common library also appears, the library does not appear twice in distinct versions.
  2. I want some of the subdependencies to pass through unmodified, and some to be grabbed by the transformer.

My current approach is to declare a Configuration which contains the tree I want transformed, and use a task to do the transform (using that Configuration as the input FileCollection) and have that task emit a FileCollection containing both modified and unmodified files. This satisfies (2), but not (1).

Other approaches:
a) I can’t implement Dependency because I can’t implement any sub-interface which allows me to be a ResolvableDependency in a plugin (that interface is internals-only). So I can’t avoid an exception from CachingDependencyResolveContext. It’s a shame, as I think this might architecturally be the ideal approach.
b) I don’t think I can declare my transformed binary as the output artifact of another subproject (although this would be neat), because depending on that other subproject would also pull in the unmodified dependencies of the subproject itself? If the other subproject put the mutated dependency tree in a non-compile configuration, then it would fail requirement (1): I’d get two slf4j’s, because the one in the alternative configuration would not be unified with the one in compile.
c) ComponentSelectionRules lets me reject an entire dependency, which thankfully does not cause the compile to fail. This means that I can set up 3 Configurations: upstream, transformed extends upstream and untransformed extends upstream and provide inverse filters on transformed and untransformed. However, if I reject a (root-ish) dependency from untransformed, I also lose its transitive dependencies, which I wanted to retain as untransformed. So this still doesn’t let me select the dependencies I want to transform and those I don’t. This approach is closest to the current Gradle philosophy?

I’m happy to provide more examples; this is all open source. I’m also happy to provide lunch as appropriate if anyone from Gradleware can help? Thank you all.