What is the default classloading strategy of PluginRegistry?

I am still finding my way around the Gradle source code so was not able to find where the default PluginRegistry is instantiated.

I am trying something VERY tactical at the moment where in a custom plugin, I extend a third-party plugin class and also recreate the properties file in my META-INF with identical plugin-id but pointing to my implementation.

This seems to work but I am not sure if it is fluke or it will always load my plug-in properties file before the third-party dependency’s.

Can someone please let me know?

If you have two plugins with the same plugin id on the build script classpath at any given time you should, for all intents and purposes, treat the resolution of that plugin as non-deterministic. Can you explain your use case a little more and perhaps we can come up with a more stable solution.

This is very a specific case where a third-party plugin I am using (in my own custom plugin) applies one of its own plugins with an undesirable side-effect (adds some repositories). Here is a summary:

  1. my plugin applies plugin x-1 2. plugin x-1 applies plugin x-2 by plugin-id 3. plugin x-2, during its application, invokes Project.afterEvaluate { configureRepo() } 4. configureRepo() does stuff I don’t want

I am not sure if there is another phase after project evaluation where I can hook in and remove those repositories and I cannot monkey-patch any of those classes since gradle-core invokes them (in Java).

So out of sheer laziness, I re-implemented only the transitive plugin without the undesirable effect (no-op configureRepo()) and re-register its plugin-id again. Do you see another option here, short of me forking the entire third-party plugin?

Since the ‘repositories’ collection is a “Iive” collection, you typically don’t have to worry about using methods like ‘afterEvaluate { }’. Instead you can do something like this:

repositories.all { repo ->

if (/condition to determine if repo shouldn’t exist/) {




The closure passed to the ‘all()’ method is executed against all items in the collection now, and in the future, so no need to worry about what phase of project evaulation this code is executed.

Brilliant. I was not aware of this “live” collection black magic. This will certainly resolve my issue without resorting to hacks.

Out of interest, are there other constructs with the same feature? Is there a list somewhere that I can look up?

Don’t worry about the question, I figured it out. Any class implementing org.gradle.api.DomainObjectCollection has this method.

Good, glad you found that. Just for your information, there are couple of extensions of that class that bring additional capabilities. The most prevalent is probably ‘NamedDomainObjectCollection’, which is the backing implementation of collections like ‘sourceSets’ and ‘configurations’.