title: Gradle: Call ant from a custom task
body: <p>I am new to gradle and trying to migrate our currently Maven based automated JAX-WS client building project, as gradle seems to provide an easier way for us to configure the builds for new projects.</p>
  
  <p>I followed this tutorial <a href="http://jaxenter.com/tutorial-gradle-soap-features-revealed-42757-2.html" rel="nofollow">here</a> and was able to generate the client classes for a WSDL endpoint. What I want to achieve now is to put the Task definition in a new DefaultTask class to keep the build.gradle file cleaner, so I created the following file, put it in a new Groovy project and made it available to my build:</p>
  
  <pre><code>class WsimportTask extends DefaultTask {
      def List&lt;String&gt; wsdlUrls
      @OutputDirectory
      File destDir
  
      @TaskAction
      def wsimport() {
          wsdlUrls.each() {
              println "run wsimport for "+ it
              ant {
                  sourceSets.main.output.classesDir.mkdirs()  
                  destDir.mkdirs()
                  taskdef(name:'wsimport',
                      classname:'com.sun.tools.ws.ant.WsImport',
                      classpath:configurations.jaxws.asPath)
                  wsimport(keep:true,
                      destdir: sourceSets.main.output.classesDir,
                      sourcedestdir: destDir,
                      wsdl: it)
              }
          }
      }
  }
  </code></pre>
  
  <p>As I want to come up with one single project that contains a subproject for each web service client that we have, I altered the build.gradle file of the main project and added:</p>
  
  <p><strong>main build.gradle</strong></p>
  
  <pre><code>subprojects {
      configurations {
          wsimport
      }
      dependencies {
          wsimport group: 'com.mycompany.gradle', name: 'tasks', version: '0.0.2-SNAPSHOT'
      }
      task wsimport(type: com.mycompany.gradle.WsimportTask) {
          destDir = file("${buildDir}/generated")
      }
      compileJava.dependsOn(wsimport)
  }
  </code></pre>
  
  <p>The subprojects itself should then only need to contain the following configuration:</p>
  
  <p><strong>subproject build.gradle</strong></p>
  
  <pre><code>buildscript {
      wsimport {
          wsdlUrls = [
              "http://...endpoint1.wsdl",
              "http://...endpoint2.wsdl"
          ]
      }
  }
  </code></pre>
  
  <p>On running gradle clean build on the main project, I get the following messages and Exception: </p>
  
  <pre><code>:clean UP-TO-DATE 
  :Subproject:clean 
  :Subproject:wsimport 
  run wsimportfor http://endpoint1.wsdl 
  :Subproject:wsimport 
  * Exception is:
  org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':Subproject:wsimport'.
  ....
  FAILED Caused by: org.gradle.api.internal.MissingMethodException: Could not find method ant() for arguments [com.mycompany.gradle.WsimportTask$_wsimport_closure1_closure2@16caac05] on task ':Subproject:wsimport'.
  </code></pre>
  
  <p>So gradle understands my configuration, applies the WSDL endpoint and calls my custom task. Then ant {} is evaluated to a local method call the method ant(), which doesn't exist. This makes perfect sense to me, but how can I achieve my goal of calling the actual ant wsimport task from within this custom gradle task?</p>
  
  <hr>
  
  <p><strong>Solution</strong> Thanks Peter for your answer. I think i do start to understand how the Task is getting wired into my build script. I paste the complete Task for future strugglers, as I don't think the whole process of creating such a task (especially the first time) is somewhat inscrutable:</p>
  
  <pre><code>class WsimportTask extends DefaultTask {
      def List&lt;String&gt; wsdlUrls
      @OutputDirectory
      File outDir
  
      @TaskAction
      def wsimport() {
          wsdlUrls.each() {
              def temp = it
              println "run wsimport for "+ temp
              project.sourceSets.main.output.classesDir.mkdirs()  
              outDir.mkdirs()
              def classpath = project.configurations.jaxws.asPath
              def destDir = project.sourceSets.main.output.classesDir
              project.ant {
                  taskdef(name:'wsimport',
                      classname:'com.sun.tools.ws.ant.WsImport',
                      classpath:classpath)
                  wsimport(keep:true,
                      destdir: destDir,
                      sourcedestdir: outDir,
                      wsdl: temp)
              }
          }
      }
  }
  </code></pre>
  
  <p>Also notable is the fact that the task must not be defined within the buildscipt block of the build.gradle file, like Peter pointed out</p>