I have something like the plugin below where I have one outer namespace and within it there is a single 'concrete' instance (mother
) of an object plus another collection (children
).
family {
mother {
firstname = 'John'
lastname = 'Cleese'
}
children {
son {
firstName = 'John'
lastName = 'Cleese'
}
daughter {
firstName = 'Jane'
lastName = 'Cleese'
}
}
}
I am able to add the collection object and read the variables based on various examples I've seen but not sure how I add the concrete instance in addition.
How do I define it on the extension object?
Code which shows the issue - I would like to add mother
as a single instance withing the plugin.
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.*
class Person
{
final String name
String firstName
String lastName
Person(String name) { this.name = name }
}
class FamilyExtension {
final NamedDomainObjectContainer<Person> children
Person mother
Person father
FamilyExtension(children) {
this.children = children
}
def children(Closure closure) {
children.configure(closure)
}
}
class FamilyPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('sayHello', type: DefaultTask) << {
println(
"Hello ${project.family.children["son"].firstName} " +
"and hello ${project.family.children["daughter"].firstName} ")
}
def children = project.container(Person)
project.extensions.create("family", FamilyExtension, children)
}
}
apply plugin: FamilyPlugin
family {
// How do I add support for this?
// mother {
// firstname = 'John'
// lastname = 'Cleese'
// }
children {
son {
firstName = 'John'
lastName = 'Cleese'
}
daughter {
firstName = 'Jane'
lastName = 'Cleese'
}
}
}
I was having a similar problem to yours, but I figured out how to create the "mother" on my case, but not the "children". The way that I accomplished this is with a nested extension object.
Here is how I did this (mine is in pure java, so you may need to make some changes to do it in Groovy - I'm very new to Groovy, so I'm not sure exactly what needs to be changed):
When you add your extension in the plugin, the class will automatically support the ExtensionAware interface, and thus can have extensions added to it. In your FamilyExtension constructor add a new extension, casting the class to ExtensionAware first:
public FamilyExtension(NamedDomainObjectContainer<Person> children) {
((ExtensionAware) this).getExtensions().create("mother",Person.class);
this.children = children;
}
This will only allow a single mother declared exactly as you have. Note, however, that it won't enforce only a single one, as you can add as many mothers as you want, but any later declarations will have the result of changing the value on that single instance, so there really is only one. You may also get a null value if the mother had not been declared, so will have to test for that (some demos say that this can happen, but in my own experiments it doesn't seem to).
To get your mother object, just cast your extension to ExtensionAware and retrieve the Person class off from that like you would get the family extension from the project
FamilyExtension fext = project.getExtensions().findByType(Person.class)
Person mother = (Person) ((ExtensionAware) fext).getExtensions().findByName("mother")
Edit:
An alternative way would be just to define a function on your extension object which accepts a closure and have the closure delegate to a new mother object. Then you could use a Boolean flag to enforce the requirement of only one mother.
private boolean mother_defined = false;
private Person mother_value = null; // or Person mother = new Person()
public void mother(Closure<?> motherdef) {
if (mother_defined) {throw new Exception("Only one mother allowed");}
mother_value = new Person();
motherdef.setDelegate(mother);
motherdef.call();
mother_defined = true;
}
Well, to add mother
closure to the family
you add the following code to the FamilyExtension
class
Person mother(Closure closure) {
mother = new Person()
project.configure(mother, closure)
return mother
}
If, at the same time you want to have children
extension inside family one you add the following code into the FamilyPlugin.apply
method
project.extensions.create("family", FamilyExtension, instantiator, project)
project.family.extensions.create("children", FamilyExtension.Children, project)
And then you add
void son(Closure closure) {
Person son = new Person()
project.configure(son, closure)
children.add(son)
}
to be able to add son
closure inside the children
one.
To see the whole project and explanation with more details please visit Github project https://github.com/andriipanasiuk/family-gradle-plugin