Groovy mixin combined with Gradle DefaultTask results in runtime error

To explain my problem in the simplest way, I’ll first show you a Groovy script that does work and then add some Gradle sauce which breaks it.

The working Groovy script:

class MyMixin {
    String myname = 'max'
}
  @Mixin(MyMixin)
class MyClass {}
  MyClass c = new MyClass()
println 'hello ' + c.myname

This prints out “hello max” as expected. Now let’s replace that MyClass with a Gradle task class. For this we extend DefaultTask and use the @TaskAction annotation.

@Mixin(MyMixin)
class MyTask extends DefaultTask {
      @TaskAction
    void sayHello() {
        println 'hello ' + myname
    }
}

If we now install this Gradle task and execute it, we get the following runtime error:

Execution failed for task ':myproject:mytask'.
> MyTask.getMyname()Ljava/lang/String;

What’s funny is that this only happens with methods returning something. ‘void’ methods execute just fine.

So the question is simple: how can I get my mixin to cooperate with my Gradle task? (FYI: it doesn’t seem to be related to inheritance; I checked that, but didn’t include it in the sample script to keep it simple. I have also tested with a runtime mixin instead of compile-time: the result is the same).

Please post the full stack trace (’-S’) and the output of ‘gradle -v’.

My apologies (first time on this forum).

Version info:

------------------------------------------------------------
Gradle 1.0-rc-3
------------------------------------------------------------
  Gradle build time: Sunday, 29 April 2012 23:51:52 o'clock UTC
Groovy: 1.8.6
Ant: Apache Ant(TM) version 1.8.2 compiled on December 20 2010
Ivy: 2.2.0
JVM: 1.7.0_02 (Oracle Corporation 22.0-b10)
OS: Windows 7 6.1 x86

Stack trace (from the actual application, which is why some names are different then the sample script):

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':test-fb-swc-as:skeleton'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:68)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)
        at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter$1.run(CacheLockHandlingTaskExecuter.java:34)
        at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAccess.java:200)
        at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:172)
        at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)
        at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:111)
        at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)
        at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter.execute(CacheLockHandlingTaskExecuter.java:32)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)
        at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:247)
        at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTaskGraphExecuter.java:192)
        at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGraphExecuter.java:177)
        at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:83)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:36)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
        at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter$1.run(TaskCacheLockHandlingBuildExecuter.java:31)
        at org.gradle.cache.internal.DefaultCacheAccess$1.create(DefaultCacheAccess.java:111)
        at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:126)
        at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:109)
        at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:103)
        at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.useCache(DefaultTaskArtifactStateCacheAccess.java:79)
        at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter.execute(TaskCacheLockHandlingBuildExecuter.java:29)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:54)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:155)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:110)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:78)
        at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:42)
        at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:28)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:201)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:174)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:170)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
        at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:31)
        at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:20)
        at org.gradle.launcher.Main.doAction(Main.java:48)
        at org.gradle.launcher.exec.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:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
        at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:32)
        at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
Caused by: java.lang.NoSuchMethodError: org.gradlefx.tasks.project.SkeletonProject.getUuid()Ljava/lang/String;
        at org.gradlefx.tasks.project.SkeletonProject_Decorated.getUuid(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaBeanProperty.getProperty(MetaBeanProperty.java:57)
        at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.getProperty(BeanDynamicObject.java:126)
        at org.gradle.api.internal.BeanDynamicObject.getProperty(BeanDynamicObject.java:82)
        at org.gradle.api.internal.CompositeDynamicObject.getProperty(CompositeDynamicObject.java:57)
        at org.gradlefx.tasks.project.SkeletonProject_Decorated.getProperty(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
        at org.gradlefx.tasks.project.AbstractProjectTask.generateProject(AbstractProjectTask.groovy:61)
        at org.gradlefx.tasks.project.SkeletonProject.super$4$generateProject(SkeletonProject.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        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.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:128)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:148)
        at org.gradlefx.tasks.project.SkeletonProject.generateProject(SkeletonProject.groovy:33)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        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.invokeMethod(BeanDynamicObject.java:196)
        at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:102)
        at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:99)
        at org.gradlefx.tasks.project.SkeletonProject_Decorated.invokeMethod(Unknown Source)
        at groovy.lang.GroovyObject$invokeMethod.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:55)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
        at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:150)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:145)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:477)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:466)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:60)
        ... 57 more

The getUuid() here is equivalent to the getMyname() method of my original example.

Looks like Groovy’s @Mixin isn’t compatible with Gradle’s own meta-programming facilities. I suggest to use Gradle’s extra properties and/or extension objects instead.

Thanks for your suggestion. I would prefer not to litter the Project’s properties with all this additional information (I assume that’s what you mean by ‘extra properties’), so I will look into these extensions instead.

Should this be registered as a bug in the JIRA?

I would prefer not to litter the Project’s properties with all this additional information (I assume that’s what you mean by ‘extra properties’)

Search for “extra properties” in the user guide. In terms of polluting the object model, I’d consider them on par with @Mixin (but they are specifically designed for Gradle).

so I will look into these extensions instead

Extension objects are the right choice for plugins. Extra properties are meant for ad-hoc use from build scripts.

Should this be registered as a bug in the JIRA?

As extra properties and extension objects are specifically designed for extending Gradle’s object model, and incompatibilities with other meta-programming based approaches are, to some degree, to be expected, I’d rather not pursue this.