Cobertura instrumentation fails in Gradle 1.2

Possibly related to the ASM upgrade mentioned in the release notes?

Exception:

13:10:39.555 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument] java.lang.IncompatibleClassChangeError: Implementing class
13:10:39.559 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.defineClass1(Native Method)
13:10:39.562 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
13:10:39.566 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
13:10:39.570 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
13:10:39.573 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
13:10:39.577 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
13:10:39.581 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
13:10:39.584 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.security.AccessController.doPrivileged(Native Method)
13:10:39.588 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
13:10:39.592 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
13:10:39.595 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
13:10:39.599 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
13:10:39.602 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.defineClass1(Native Method)
13:10:39.606 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
13:10:39.609 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
13:10:39.613 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
13:10:39.617 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
13:10:39.621 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
13:10:39.624 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
13:10:39.628 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.security.AccessController.doPrivileged(Native Method)
13:10:39.631 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
13:10:39.635 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
13:10:39.639 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
13:10:39.642 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
13:10:39.645 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.Class.getDeclaredMethods0(Native Method)
13:10:39.649 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
13:10:39.653 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.Class.getMethod0(Class.java:2685)
13:10:39.656 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at java.lang.Class.getMethod(Class.java:1620)
13:10:39.660 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:492)
13:10:39.664 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument]
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:484)
13:10:39.903 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:cobertura-instrument] Exception in thread "main"

Cobertura dependencies:

testRuntime - Classpath for running the compiled test classes.
...
\--- net.sourceforge.cobertura:cobertura:1.9.4.1
     +--- oro:oro:2.0.8
     +--- asm:asm:3.0 -> 3.2 (*)
     +--- asm:asm-tree:3.0 -> 3.2 (*)
     +--- log4j:log4j:1.2.9
     \--- org.apache.ant:ant:1.7.0
          \--- org.apache.ant:ant-launcher:1.7.0

Simply excluding the ASM group from the Cobertura dependencies didn’t work. Nor did defining a client module dependency on Cobertura in which I forced the version to 4.0. But if ASM 4 breaks binary compatibility, I guess those options are doomed to failure.

I am using Gradle 1.2, Oracle JDK 1.7.0_05.

Which cobertura plugin are you using? There are two open source ones, and they have different levels of support and ways in which they setup cobertura.

We are using home-brewed support created last year, which mostly follows the Gradle Cookbook: http://docs.codehaus.org/display/GRADLE/Cookbook#Cookbook-usingCobertura

This is the snippet for building our custom plugins, which is where I had the problem. In the custom plugins themselves, we cleaned this up a bit (e.g. no more copy/backup/replace): https://gist.github.com/3713721

I just tried ‘com.mapvine:gradle-cobertura-plugin:0.3.1’ but got a similar error:

org.gradle.api.GradleException: Could not generate a proxy class for class org.gradle.api.internal.project.DefaultProject.
        at org.gradle.api.internal.AbstractClassGenerator.generate(AbstractClassGenerator.java:187)
        at org.gradle.api.internal.ClassGeneratorBackedInstantiator.newInstance(ClassGeneratorBackedInstantiator.java:36)
        at org.gradle.api.internal.project.ProjectFactory.createProject(ProjectFactory.java:47)
        at org.gradle.api.internal.project.ProjectFactory.createProject(ProjectFactory.java:31)
        at org.gradle.testfixtures.internal.ProjectBuilderImpl.createProject(ProjectBuilderImpl.java:72)
        at org.gradle.testfixtures.ProjectBuilder.build(ProjectBuilder.java:99)
        at org.gradle.testfixtures.ProjectBuilder$build.call(Unknown Source)
        at com.copyright.rup.scm.gradle.plugins.PluginTestUtils.getTestProject(PluginTestUtils.groovy:14)
        at com.copyright.rup.scm.gradle.plugins.PluginTestUtils$getTestProject.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
        at com.copyright.rup.scm.gradle.plugins.RupJavaPluginTest.applyPlugin(RupJavaPluginTest.groovy:17)
          Caused by:
        java.lang.IncompatibleClassChangeError: Found interface org.objectweb.asm.MethodVisitor, but class was expected
            at org.gradle.api.internal.AsmBackedClassGenerator$ClassBuilderImpl.addGetter(AsmBackedClassGenerator.java:470)
            at org.gradle.api.internal.AsmBackedClassGenerator$ClassBuilderImpl.addGetter(AsmBackedClassGenerator.java:464)
            at org.gradle.api.internal.AsmBackedClassGenerator$ClassBuilderImpl.mixInGroovyObject(AsmBackedClassGenerator.java:430)

It’s because of the ASM upgrade: http://gradle.org/docs/current/release-notes#upgrade-to-asm-4.0

Any chance you can upgrade the version of ASM you are using?

I tried, but maybe I am not doing it correctly; please let me know!

ASM is a dependency of my project via two paths. One is Cobertura, one is tberglund’s gradle-liquibase-plugin.

I declared this to upgrade ASM for Cobertura:

testRuntime module('net.sourceforge.cobertura:cobertura:1.9.4.1') {
        dependency 'oro:oro:2.0.8'
        dependency 'org.ow2.asm:asm:4.0'
        dependency 'org.ow2.asm:asm-tree:4.0'
        dependency 'log4j:log4j:1.2.9'
        dependency 'org.apache.ant:ant:1.7.0'
    }

And I commented out the gradle-liquibase-plugin dependency for the moment.

But then Cobertura has an error, I think because it wants the old ASM (see below). Unless I’m missing something, Cobertura itself would have to be re-released for ASM 4.

[ant:cobertura-instrument] java.lang.NoClassDefFoundError: org/objectweb/asm/ClassAdapter
[ant:cobertura-instrument]
    at java.lang.ClassLoader.defineClass1(Native Method)
[ant:cobertura-instrument]
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
[ant:cobertura-instrument]
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
[ant:cobertura-instrument]
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
[ant:cobertura-instrument]
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
[ant:cobertura-instrument]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
[ant:cobertura-instrument]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
[ant:cobertura-instrument]
    at java.security.AccessController.doPrivileged(Native Method)
[ant:cobertura-instrument]
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
[ant:cobertura-instrument]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
[ant:cobertura-instrument]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
[ant:cobertura-instrument]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
[ant:cobertura-instrument]
    at java.lang.Class.getDeclaredMethods0(Native Method)
[ant:cobertura-instrument]
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
[ant:cobertura-instrument]
    at java.lang.Class.getMethod0(Class.java:2685)
[ant:cobertura-instrument]
    at java.lang.Class.getMethod(Class.java:1620)
[ant:cobertura-instrument]
    at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:492)
[ant:cobertura-instrument]
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:484)
[ant:cobertura-instrument] Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.ClassAdapter
[ant:cobertura-instrument]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
[ant:cobertura-instrument]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
[ant:cobertura-instrument]
    at java.security.AccessController.doPrivileged(Native Method)
[ant:cobertura-instrument]
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
[ant:cobertura-instrument]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
[ant:cobertura-instrument]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
[ant:cobertura-instrument]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
[ant:cobertura-instrument]
    ... 18 more
[ant:cobertura-instrument] Exception in thread "main"

The question is whether the classpaths need to mix.

  1. Does cobertura introduce runtime dependencies to test execution? 2. Does cobertura instrumentation require runtime dependencies on the classpath?

Good point. My implementation uses the ‘testRuntime’ configuration, and it probably shouldn’t. I’ve learned more about Gradle since writing this.

But as noted above, I tried using ‘com.mapvine:gradle-cobertura-plugin:0.3.1’. This plugin creates a separate ‘cobertura’ configuraion, yet I still see the ‘IncompatibleClassChangeError’ quoted above. I followed the instructions here and thus added

buildscript {
    dependencies {
        classpath 'com.mapvine:gradle-cobertura-plugin:0.3.1'
    }
}

Per the stacktrace, the failure is in calling Gradle’s ‘ProjectBuilder’. If that depends on ASM 4 and we’ve already put ASM 3 on the buildscript classpath for Cobertura …

Here’s a stripped-down sample project that recreates the error: https://github.com/dstine/gradle-asm

I’ve submitted a pull request for that plugin that fixes the issue.

Luckily, cobertura is compatible with asm 4. Which means you should put cobertura and it’s dependencies last on the test runtime classpath. If you do that, it all works.

I’m checking out the pull request and verifying the fix.

I’ll let you all know when there’s a new version published, probably in a few hours.

Thanks, Luke and Eric.

With Luke’s help, I have pushed version 1.0 of our cobertura plugin to Maven Central. It will take a couple hours to become available. Please update your buildScript to:

buildscript {

dependencies {

classpath ‘com.mapvine:gradle-cobertura-plugin:1.0’

}

}

This release slightly changes how you declare your sources for code coverage. Configure cobertura like so:

cobertura {

format = ‘xml’ // Optional

includes = [’/*.java’, '/*.groovy’]

}

Thanks again to Luke for his huge help.

The new version of the plugin works for my build. Thanks again.

Great news :slight_smile: Open source at its finest. Thanks for the prompt response Eric.

Thanks for letting me know about the problem right away and all of the helpful code, Luke :slight_smile: