Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding object instance to gradle plugin extension

Tags:

gradle

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'
      }
  }
}
like image 390
LK__ Avatar asked Feb 16 '15 19:02

LK__


People also ask

What is EXT in build Gradle?

Extra properties extensions allow new properties to be added to existing domain objects. They act like maps, allowing the storage of arbitrary key/value pairs. All ExtensionAware Gradle domain objects intrinsically have an extension named “ext” of this type.

What is the use of Buildscript in Gradle?

buildscript: This block is used to configure the repositories and dependencies for Gradle. dependencies: This block in buildscript is used to configure dependencies that the Gradle needs to build during the project.

What is subprojects in Gradle?

The subproject producer defines a task named buildInfo that generates a properties file containing build information e.g. the project version. You can then map the task provider to its output file and Gradle will automatically establish a task dependency.

How to add an extension to a Gradle project?

The extension object is added to the plugin list with the name greeting. This object, then becomes available as a project property with the same name as the extension object. Gradle adds a configuration closure for each extension object, so you can group the settings together.

How to create a custom plugin in Gradle?

While creating a custom plugin, you need to write an implementation of plugin. Gradle instantiates the plugin and calls the plugin instance using Plugin.apply () method. The following example contains a greeting plugin, which adds a hello task to the project.

Where can I find more on publishing projects to Gradle repository?

More on publishing projects to Gradle repository can be found in Gradle Plugin Portal Documentation. 5.5. Java Gradle Development Plugin When we're writing our plugins in Java, we can benefit from the Java Gradle Development Plugin.

What is a property object in Gradle?

In Gradle Property objects are a way to refer to a value before it’s actually set. This is useful with plugins and tasks since the property value may be referenced before its actual value has been configured in the build script. Use of abstract: the FileDiffExtension class itself and its methods are abstract.


2 Answers

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

like image 70
Andrew Panasiuk Avatar answered Oct 09 '22 14:10

Andrew Panasiuk


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;
}
like image 4
Matthew Avatar answered Oct 09 '22 15:10

Matthew