Hello! I'm having difficulties with the Groovy DSL...
# plugin-development
j
Hello! I'm having difficulties with the Groovy DSL, specifically that I am unable to use the implicit
it
on actions. The script will compile and the
doCall
is intercepted to try and set the property of the current dynamic object. And this is not including types that are `DslObject`s or
DynamicObjectAware
. Both method calls and the short-hand for getters and setters don't work. Basically, this works:
Copy code
accessTransformers.register {
    it.config = project.file('accesstransformer.cfg')
}
and this doesn't:
Copy code
accessTransformers.register {
    config = project.file('accesstransformer.cfg')
}
why is that? and is there anything I can realistically do about this without needing to use something like a domain object container? For reference, this is the method they are calling in this example
Copy code
default AccessTransformersContainer register(Action<? super AccessTransformersContainer.Options> options) {
    return this.register(AccessTransformersExtension.DEFAULT_ATTRIBUTE, options);
}
and this is the exception being thrown:
Copy code
Caused by: groovy.lang.MissingPropertyException: Could not set unknown property 'config' for project ':at-gradle-demo' of type org.gradle.api.Project.
	at org.gradle.internal.metaobject.AbstractDynamicObject.setMissingProperty(AbstractDynamicObject.java:118)
	at org.gradle.groovy.scripts.BasicScript$ScriptDynamicObject.setMissingProperty(BasicScript.java:170)
	at org.gradle.internal.metaobject.AbstractDynamicObject.setProperty(AbstractDynamicObject.java:76)
	at org.gradle.api.internal.project.DefaultDynamicLookupRoutine.setProperty(DefaultDynamicLookupRoutine.java:42)
	at org.gradle.groovy.scripts.BasicScript.setProperty(BasicScript.java:74)
	at org.gradle.internal.classpath.declarations.GroovyDynamicDispatchInterceptors.callInstrumentedSetProperty(GroovyDynamicDispatchInterceptors.java:102)
	at org.gradle.internal.classpath.declarations.GroovyDynamicDispatchInterceptors.intercept_setProperty(GroovyDynamicDispatchInterceptors.java:89)
	at build_es5ivf5z9jwb4t9pnjernbno6$_run_closure1.doCall$original([path]/at-gradle-demo/build.gradle:9)
If this is a bug, let me know so I can report it. But for now I'm under the assumption that there's a good reason for this.
e
https://groovy-lang.org/closures.html#_delegation_strategy_2 in general, a name
config
within a Groovy closure may resolve to
owner.config
,
delegate.config
, or
self.config
. none of those are
it.config
, unless the closure had its delegate changed to be the same as it
but that only matters for
groovy.lang.Closure
, not
org.gradle.api.Action
j
I'll try
Closure
and making sure I set the delegate correctly then. I tried earlier just using
Closure.DELEGATE_FIRST
without anything else.
Aha! Thank you for the pointer! I believe the trick was changing the context class loader. Either that, or it didn't like that the delegate was the same as the owner.
a
I think this is a similar issue as discussed here: https://github.com/gradle/gradle/issues/33403 See this comment: https://github.com/gradle/gradle/issues/33403#issuecomment-2863555460 Tl;dr: if you instantiate your object via
ObjectFactory
Gradle will add
Closure
methods at runtime for Groovy and then implicit
it
should work. But if you create objects manually (e.g. via constructor) then this won't work. I guess in your case, you are instantiating
AccessTransformersContainer.Options
manually.
j
Yes, I was. Though, making a utility method that did what
AbstractTask#doExecute
did worked for me. So it may have been a class loader moment(?)
a
I see what
doExecute
does, that looks like magic 🙂. I wouldn't recommend using that, unless you really know how Groovy works. Using ObjectFactory is safer option in the long run, and I think it's also simpler to understand
j
Using ObjectFactory is what I'll probably end up doing. But will still play around with that magic to try and get a grip on what's going on
👍 1