How can I customize the behaviour of the Eclipse plugin for all subprojects?

I need to apply the same modifications to the generated .classpath in a large number of sub-projects. The modification uses the withXml hook:

eclipse.classpath.file {
    withXml {
        ...
    }
}

Ideally, I’d like to apply this same hook to all such that “gradle eclipse” at the parent will generate modified .classpath files for all subprojects. But I can’t seem to get the customized hook to stick or inject just from the parent build.gradle file. I’m pretty sure this just me not fully understanding the gradle lifecycle and not knowing exactly when the Eclipse plugin’s configuration for each subproject is available for customization.

Can anyone help, please?

Have you tried placing the above configuration inside of a ‘subprojects {…}’ configuration block?

Yes, that was my first attempt.

subprojects {
    eclipse.classpath.file {
        withXml {
            ...
        }
    }
}

This doesn’t add the withXml hook into the sub-projects (Gradle v2.2, btw).

It appears to me that the eclipse classpath configuration object doesn’t exist for a project until later when the task is actually executed.

The ‘withXml’ block should be executed when the classpath file is created. It is effectively deferred until then. Can you confirm that it definitely is not being executed when calling the ‘eclipse’ task? Perhaps by putting some kind of ‘println’ statement in there?

This is where I got stuck. If you add in some log output (within withXml in the root project), the output looks like this (for our project):

$> gradle eclipsePath
:eclipseClasspath
Here!
Here!
Here!
Here!
Here!
Here!
:eclipseJdt
:eclipseProject
:eclipse
:eji:eclipseClasspath
:eji:eclipseJdt
:eji:eclipseProject
:eji:eclipse
:tresrv:eclipseClasspath
:tresrv:eclipseJdt
:tresrv:eclipseProject
:tresrv:eclipse
:trewfe:eclipseClasspath
:trewfe:eclipseJdt
:trewfe:eclipseProject
:trewfe:eclipse
:util:eclipseClasspath
:util:eclipseJdt
:util:eclipseProject
:util:eclipse
:wfeutil:eclipseClasspath
:wfeutil:eclipseJdt
:wfeutil:eclipseProject
:wfeutil:eclipse

(Note that this is the execution after removing/cleaning any existing .classpath files - otherwise eclipseClasspath does nothing).

The withXml in the parent is being run (for each child?!?) - but too early, in the parent execution! Each child .eclipseClasspath task runs with unmodified configuration.

You might want to use the ‘whenMerged { }’ configuration block then if you need the ‘EclipseClasspath’ object to exist.

The whenMerged hook has the same issues as withXml - it is executed in the parent for each sub-project before the EclipseClasspath object is created for each sub-project.

Is there a mechanism in gradle to attach the withXml/whenMerged for each subproject just before the eclipseClasspath task is executed?

You may need to ensure that you are applying the ‘eclipse’ plugin in the ‘subprojects {…}’ block as well. It looks like it isn’t finding the eclipse extension on the subproject and therefore delegating to the root project.

Hmm…that seems inconvenient since not all subprojects need/have the eclipse plugin. It seems awkward for the parent project to pre-determine which subprojects need the eclipse plugin.

So, I’ve just gone with an inherited method in the parent that subprojects can optionally use if the use the eclipse project to “correct” the classpath.

Thanks for your help.

In Gradle 2.3 its possible to use the new ‘PluginManager’ interface to accomplish what you want. This would solve the problem of only applying to projects with the ‘eclipse’ plugin and also deferring configuration until after the plugin was applied. For example:

subprojects {

pluginManager.withPlugin(‘eclipse’) {

// configure eclipse plugin

}

}

Edit: You can get a similar behavior in earlier versions using ‘plugins.withId()’.