title: Correct way to define a Gradle plugin property extension with Java?
body: <p>I'm trying to create a Gradle plugin in Java that has property extensions (not conventions, as this is apparently the <a href="https://stackoverflow.com/questions/17589206/gradle-plugin-convention-vs-extension">old</a>, <a href="http://forums.gradle.org/gradle/topics/how_do_you_use_a_conventionmapping_to_do_the_following" rel="nofollow noreferrer">wrong</a> way). For the record, I'm working with Gradle 1.6 on a Linux machine (Ubuntu 12.04).</p>
  
  <p>I've gotten as far as figuring out that the this should be done in the Plugin class definition. Here is A way of adding an extension. Create an extension class that contains your properties:</p>
  
  <pre><code>public class MyPluginExtensions {
  
      File sourceDir;
      File outputDir;
  
      public MyPluginExtensions(Project project) {
          this.project = project;
          sourceDir = new File(project.getProjectDir(), "src");
          outputDir = new File(project.getBuildDir(), "out");
      }
  
  }
  </code></pre>
  
  <p>Now add these extensions to the project in the main plugin class:</p>
  
  <pre><code>public class MyPlugin implements Plugin&lt;Project&gt; {
  
      @Override
      public void apply(Project project) {
  
          Map&lt;String,Object&gt; taskInfo = new HashMap&lt;String,Object&gt;();
          taskInfo.put("type", MyPluginTask.class);
          taskInfo.put("description", "Generates blah from blah.");
          taskInfo.put("group", "Blah");
          Task myPluginTask = project.task(taskInfo, "myPluginTask");
  
          // Define conventions and attach them to tasks
          MyPluginExtensions extensions = new MyPluginExtensions(project);
          myPluginTask.getExtensions().add(
                  "sourceDir", 
                  extensions.sourceDir);
          myPluginTask.getExtensions().add(
                  "outputDir", 
                  extensions.outputDir);
      }
  }
  </code></pre>
  
  <p>This approach, however, doesn't seem to be correct. A new project property is shows up in the <code>project.ext</code> namespace. I expect to be able to address the plugin extensions as:</p>
  
  <pre><code>in my build.gradle:
  myPluginTask.sourceDir = file('the/main/src')
  myPluginTask.outputDir = file('the/output')
  </code></pre>
  
  <p>However, when I put such things in a gradle script that uses my plugin and try to set this property, gradle tells me I can't set it:</p>
  
  <pre><code>* What went wrong:
  A problem occurred evaluating script.
  &gt; There's an extension registered with name 'sourceDir'. You should not reassign it via a property setter.
  </code></pre>
  
  <p>So, what's the right way to add property extensions for a task in a Java-based Gradle plugin?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Based on some other SO posts, I tried just adding my extensions object in one shot:</p>
  
  <pre><code>// first attempt:
  //myPluginTask.getExtensions().add("sourceDir", extensions.sourceDir);
  //myPluginTask.getExtensions().add("outputDir",extensions.outputDir);
  
  // second attempt
  myPluginTask.getExtensions().add("myPluginTask", extensions);
  </code></pre>
  
  <p>This appears to work. However, Gradle is now complaining that I've added a dynamic property:</p>
  
  <pre><code>Deprecated dynamic property: "sourceDir" on "task ':myPluginTask'", value: "/Users/jfer...".
  </code></pre>
  
  <p>So, again, what's the right way to add a plugin extension property?</p>
  
  <p><strong>EDIT 2</strong></p>
  
  <p>So, taking yet another shot at this, I'm adding the extension to the project object and using the create method instead:</p>
  
  <pre><code>// first attempt:
  //myPluginTask.getExtensions().add("sourceDir", extensions.sourceDir);
  //myPluginTask.getExtensions().add("outputDir",extensions.outputDir);
  
  // second attempt
  // myPluginTask.getExtensions().add("myPluginTask", extensions);
  
  // third attempt
  project.getExtensions().create("myPluginTask", MyPluginExtensions.class, project);
  </code></pre>
  
  <p>However, this fails for a couple of reasons:</p>
  
  <ol>
  <li>Creating a properties extension with the same name ("myPluginTask") as the task creates a collision between the task name and extension name, causing the task to disappear from gradle's perspective (and throw oblique errors, such as "No such property: dependsOn for class ...MyPluginExtensions").</li>
  <li>If I provide a name that does not collide with a task name (e.g., "myPluginPropExt"), the create() method works, but DOES NOT add the extension in its own namespace as expected (e.g., <code>project.myPluginPropExt.propertyName</code> and instead adds it in the project namespace (e.g., <code>project.propertyName</code>) which is not correct and causes Gradle to throw a bunch of "deprecated dynamic property" warnings.</li>
  </ol>