Convention mapping for plugins

Hi,

as a plugin developer what is the recommended way of reading convention properties and setting the values to fields of classes that implement DefaultTask? In the past all my Task classes used to extend the internal class org.gradle.api.internal.ConventionTask and had to access fields using getter method. Extending ConventionTask has multiple drawbacks:

a) You can only access the values via getter methods which fields very clunky.

b) ConventionTask is an internal class which might be deprecated.

In the future I’d like to stay away from using ConventionTask and have my tasks implement DefaultTask. However, I am having trouble setting the fields with values that I read from my Convention. It pretty much boils down to the problems reported in this posting. I think plugin developers often times simply want to read convention properties when creating a task and set them as field values. Having to use convention mapping simply feels like more work than there should be.

From your point of view is there a way to get this working? I read there will be an extension mechanism for plugins with 1.0-milestone-5. Is there any kind of documentation on how this is going to work and how to use it?

Thanks,

Ben

Please don’t double-post here and on the mailing list. Below is my answer from the list:

A couple of points:

  • You don’t need to extend ConventionTask to get a “conventionMapping” property (and mechanism). DefaultTask is good enough.

  • Solving the evaluation order problem isn’t easy. At the moment it requires convention mapping and explicit use of getters. Maybe we’ll come up with something better in the future.

  • The new extension mechanism is not related to the evaluation order problem. It’s “just” a nicer way to implement a configuration block like:

reporting {

}

This can now be done by registering an object as a “reporting” extension. The closure will then configure the object.

Thanks for your reply. That clarifies things. Sorry about double-posting. In the future I will only post here.

One thing I’d like to do is separate the configuration phase into a few pieces. One such separation would be to first configure the plugin’s domain objects (eg convention/extension objects), and then secondly create and configure the tasks. This way, Gradle can guarantee to the plugin that the domain objects will not change, and so the plugin can simply use the values straight out of the domain objects.

I doubt this will make it into Gradle 1.0. We can probably come up with a way to introduce this post-1.0 in a backwards-compatible way, and then remove the old way of doing things in 2.0.

My vision for tackling evaluation order problems is more implicit laziness. Basically, if a task’s configuration block is only evaluated when “needed”, explicit laziness (convention mapping etc.) isn’t required. Of course it isn’t quite as simple as that, and there are many details to be worked out.

Is the explicit getter still needed to retrieve value from the convention mapping, or are there better ways now?

To explain a little bit.

I was testing if my task was retrieving the convention value using: println “${xlibDir}” But this was always returning null, so I had the impression it was not working.

I changed it to: println “${getXlibDir()}” and then it’s working again.

I had to search some time to find http://gradle.1045684.n5.nabble.com/Task-is-your-conventionMapping-not-working-td3359346.html

However now when I do something like:

project.copy {
 from project.zipTree(artifact.file)
 into "${xlibDir}/${module.name}"
}

Then I don’t have to use the getter. So eventually it works, except using the property in a println.

Hmm, and when doing this:

if (!lockFile().exists()) {
 lockFile().withWriter { out ->

it won’t work and I need the explicit getter.

So maybe a rule of dumb is to always use the getter.

Convention mapping only works if the getter is called. Groovy automatically calls the getter if you use property syntax, except when the property is declared in the same class.

Peter could you prepare whole example? Because this case in not very well documented and causes questions

Sorry to re-ignite this question. I may be a victim of too much information. I’ve read a lot of different implementations, but I cant seem to make heads or tails of the best practice.

I’m currently trying to write a plugin for SoapUI and I have sketched the tasks I want, but some have a large number of properties. I would like to map these to a convention (I’m assuming we can use extension and convention words interchangeably), but this seems like an extremely laborious task.

Given the scenario where a task has 20 properties; first, create a convention bean with the equivalent number of properties then when I add the task to my plugin map the convention and task properties.

Is this correct?