NullPointerException from Gradle/Cobertura instrumentation

After upgrading from Gradle 1.0 to 1.1, my Cobertura instrumentation task is generating an NPE:

[ant:cobertura-instrument] java.lang.NullPointerException
        at org.apache.tools.ant.taskdefs.Redirector.createStreams(Redirector.jav
a:568)
        at org.apache.tools.ant.taskdefs.Redirector.createHandler(Redirector.jav
a:757)
        at org.apache.tools.ant.taskdefs.Java.fork(Java.java:786)
        at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:214)
        at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
        at net.sourceforge.cobertura.ant.InstrumentTask.execute(InstrumentTask.j
ava:199)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.jav
a:106)
        at groovy.util.AntBuilder.performTask(AntBuilder.java:260)
        at groovy.util.AntBuilder.nodeCompleted(AntBuilder.java:220)
        at org.gradle.api.internal.project.ant.BasicAntBuilder.nodeCompleted(Bas
icAntBuilder.java:71)
        at groovy.util.BuilderSupport.doInvokeMethod(BuilderSupport.java:147)
        at groovy.util.AntBuilder.doInvokeMethod(AntBuilder.java:170)
        at org.gradle.api.internal.project.ant.BasicAntBuilder.doInvokeMethod(Ba
sicAntBuilder.java:86)
        at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:64)
        at org.gradle.api.internal.project.DefaultAntBuilder.super$3$invokeMetho
d(DefaultAntBuilder.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1047)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper
N(ScriptBytecodeAdapter.java:128)
        at org.gradle.api.internal.project.DefaultAntBuilder.invokeMethod(Defaul
tAntBuilder.groovy:37)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeOnDelega
tionObjects(ClosureMetaClass.java:407)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(C
losureMetaClass.java:348)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(Po
goMetaClassSite.java:66)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent
(CallSiteArray.java:46)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
tractCallSite.java:133)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
tractCallSite.java:145)
        at cobertura_6vnkfp8bm7kutgjrkf4tuon041$_run_closure3_closure8_closure9.
doCall(C:\Users\chris\work\PAL-CPOF-SHELL\branches\cpof-7\tasklearning\gradle\sc
ripts\cobertura.gradle:33)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(C
losureMetaClass.java:272)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at groovy.lang.Closure.call(Closure.java:412)
        at groovy.lang.Closure.call(Closure.java:425)
        at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:141)
        at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:90)
        at org.gradle.api.internal.project.AbstractProject.ant(AbstractProject.j
ava:845)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1047)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMeth
od(BeanDynamicObject.java:196)
        at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObj
ect.java:102)
        at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(Composite
DynamicObject.java:99)
        at org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.java:
83)
        at sun.reflect.GeneratedMethodAccessor26.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
        at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:804)
          at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:
1096)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1049)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:697)
        at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java
:44)
        at groovy.lang.Script.invokeMethod(Script.java:78)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeOnDelega
tionObjects(ClosureMetaClass.java:423)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(C
losureMetaClass.java:348)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:697)
        at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java
:44)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeOnDelega
tionObjects(ClosureMetaClass.java:423)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(C
losureMetaClass.java:348)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(Po
goMetaClassSite.java:66)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent
(CallSiteArray.java:46)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
tractCallSite.java:133)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
tractCallSite.java:141)
        at cobertura_6vnkfp8bm7kutgjrkf4tuon041$_run_closure3_closure8.doCall(C:
\Users\chris\work\PAL-CPOF-SHELL\branches\cpof-7\tasklearning\gradle\scripts\cob
ertura.gradle:32)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(C
losureMetaClass.java:272)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877)
        at groovy.lang.Closure.call(Closure.java:412)
        at groovy.lang.Closure.call(Closure.java:425)
        at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(Abstra
ctTask.java:447)
        at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(Abstra
ctTask.java:431)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.ex
ecuteActions(ExecuteActionsTaskExecuter.java:60)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.ex
ecute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExec
uter.execute(PostExecutionAnalysisTaskExecuter.java:34)
        at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter
$1.run(CacheLockHandlingTaskExecuter.java:34)
        at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAcc
ess.java:200)
        at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(Def
aultCacheAccess.java:172)
        at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(Def
aultCacheAccess.java:198)
        at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunning
Operation(DefaultPersistentDirectoryStore.java:137)
        at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCache
Access.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)
        at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter
.execute(CacheLockHandlingTaskExecuter.java:32)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.exec
ute(SkipUpToDateTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execut
e(ValidatingTaskExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecu
ter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter
.execute(SkipTaskWithNoActionsExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execut
e(SkipOnlyIfTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter
.execute(ExecuteAtMostOnceTaskExecuter.java:42)
        at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailur
e(AbstractTask.java:247)
        at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTask
GraphExecuter.java:192)
        at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGr
aphExecuter.java:177)
        at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGrap
hExecuter.java:83)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTask
ExecutionAction.java:36)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecute
r.java:61)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExec
uter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecu
ter.java:67)
        at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExe
cuter$1.run(TaskCacheLockHandlingBuildExecuter.java:31)
        at org.gradle.cache.internal.DefaultCacheAccess$1.create(DefaultCacheAcc
ess.java:111)
        at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAcc
ess.java:126)
        at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAcc
ess.java:109)
        at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(De
faultPersistentDirectoryStore.java:129)
        at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCache
Access.useCache(DefaultTaskArtifactStateCacheAccess.java:79)
        at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExe
cuter.execute(TaskCacheLockHandlingBuildExecuter.java:29)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecute
r.java:61)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExec
uter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecu
ter.java:67)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildEx
ecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecute
r.java:61)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecute
r.java:54)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(Default
GradleLauncher.java:155)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradle
Launcher.java:110)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLaun
cher.java:78)
        at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.jav
a:38)
        at org.gradle.launcher.exec.InProcessGradleLauncherActionExecuter.execut
e(InProcessGradleLauncherActionExecuter.java:39)
        at org.gradle.launcher.exec.InProcessGradleLauncherActionExecuter.execut
e(InProcessGradleLauncherActionExecuter.java:25)
        at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:50)
        at org.gradle.launcher.cli.ActionAdapter.execute(ActionAdapter.java:30)
        at org.gradle.launcher.cli.ActionAdapter.execute(ActionAdapter.java:22)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.
execute(CommandLineActionFactory.java:200)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.
execute(CommandLineActionFactory.java:173)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(
CommandLineActionFactory.java:169)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(
CommandLineActionFactory.java:138)
        at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionRep
ortingAction.java:33)
        at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionRep
ortingAction.java:22)
        at org.gradle.launcher.Main.doAction(Main.java:48)
        at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
        at org.gradle.launcher.Main.main(Main.java:39)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBoots
trap.java:50)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.j
ava:32)
        at org.gradle.launcher.GradleMain.main(GradleMain.java:26)

The Gradle script in question is mostly copied from the Gradle Cookbook:

// $Id: cobertura.gradle 6289 2012-04-04 21:54:43Z cjones $
// Use Cobertura to do test coverage analysis. Copied from
// http://wiki.gradle.org/display/GRADLE/Cookbook#Cookbook-usingCobertura
  def cobSerFile = "${project.buildDir}/cobertura.ser"
def srcInstr = file("${sourceSets.main.output.classesDir}-instr")
  dependencies {
        testRuntime 'net.sourceforge.cobertura:cobertura:1.9+'
}
  task coberturaSetup {
    doLast {
        ant.taskdef(resource:'tasks.properties',
                    classpath: configurations.testRuntime.asPath)
    }
}
  task coberturaInstrument(dependsOn: [coberturaSetup, classes]) {
    inputs.files sourceSets.main.output
    outputs.dir srcInstr
    doLast {
        // delete data file for cobertura, otherwise coverage would be added
        ant.delete(file:cobSerFile, failonerror:false)
        // Delete instrumented classes before recreating them
        ant.delete(dir: srcInstr.path, failonerror: false)
        srcInstr.mkdirs()
        if(!sourceSets.main.output.classesDir.exists()) {
            return
        }
        // Instrument the source files
        ant {
            'cobertura-instrument'(datafile: cobSerFile, toDir: srcInstr) {
                fileset(dir: sourceSets.main.output.classesDir.path) {
                    include(name: '**/*.class')
                }
            }
        }
    }
}
test.dependsOn(coberturaInstrument)
  // Change the test task's classpath to include instrumented classes
// before the original ones.
test.doFirst {
    classpath = classpath - files(sourceSets.main.output.classesDir)
    classpath = classpath + files(srcInstr)
    classpath = classpath + files(sourceSets.main.output.classesDir)
}
  // Set the appropriate system property so the running tests can find
// the cobertura data file.
test {
    // for TestNG:
    systemProperties ["net.sourceforge.cobertura.datafile"] = cobSerFile
    // for JUnit:
    //systemProperties ["net.sourceforge.cobertura.datafile": cobSerFile]
}
  // Build the cobertura report.
task coberturaReport(dependsOn: [coberturaSetup, test]) {
    inputs.files cobSerFile
    outputs.dir "$buildDir.name/reports/cobertura"
    doLast {
        def gproj = project
        if(!file(cobSerFile).exists()) {
            return
        }
        ant {
            'cobertura-report'(destdir:"${gproj.buildDir.name}/reports/cobertura",
                               format:'xml', datafile:cobSerFile) {
                sourceSets.main.java.srcDirs.each { srcDir ->
                    if(srcDir.isDirectory()) {
                        fileset(dir: srcDir.path) {
                            include(name: '**/*.java')
                        }
                    }
                }
            }
        }
    }
}
check.dependsOn(coberturaReport)

I should have mentioned: The error happened on line 33 of the script, which is this:

'cobertura-instrument'(datafile: cobSerFile, toDir: srcInstr) {
                fileset(dir: sourceSets.main.output.classesDir.path) {
                    include(name: '**/*.class')
                }
            }

If the problem is really related to moving from 1.0 to 1.1, then it’s more likely caused by something peripheral than by a code change in Gradle. The only change that comes to my mind is upgrading from Ant 1.8.2 to 1.8.4. Looking at Ant’s Redirector.java:568, this line can’t throw an NPE. I guess it must be 569, but still it’s unclear to me why an NPE would occur in that line.

This is fixed in Gradle 1.2.