I've been searching in the official Groovy documentation how to replace a call like
MyOuterClass.this
inside a nested class MyInnerClass, but they don't seem to talk about this difficulty. And I did not find by Googling neither.
So, let's say I have this code :
class MyOuterClass {
class MyInnerClass {
}
}
How can I call the this pointer of MyOuterClass inside a method of MyInnerClass ?
Here is an attempt :
public class Outer {
def sayHello() {println "Hello !"}
public class Inner {
def tellHello(){
Outer.this.sayHello()
}
}
}
def objOuter = new Outer()
def objInner = new Outer.Inner()
objInner.tellHello()
and here the error stacktrace :
java.lang.NullPointerException: Cannot invoke method sayHello() on null object
at Outer$Inner.tellHello(inner_outer.groovy:5)
at Outer$Inner$tellHello.call(Unknown Source)
at inner_outer.run(inner_outer.groovy:12)
(I am using the Groovy 2.4.5 version).
The only problem is that you're not passing the outer object to your new Inner class statement, use this:
def objOuter = new Outer()
def objInner = new Outer.Inner(objOuter)
Instead of:
def objOuter = new Outer()
def objInner = new Outer.Inner()
And your code will works,
Hope this helps,
Related
I'm running the following code (in Jenkins script console):
def sayHello() {
println "Hello"
}
class MyClass {
MyClass() {
sayHello()
}
}
def a = new MyClass()
In all the good faith, I expect the constructor code to call the function that will print Hello.
Instead I get
groovy.lang.MissingMethodException: No signature of method: MyClass.sayHello() is applicable for argument types: () values: []
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
What is going on here? I can't call the function from inside the class?
You get the error because you cannot access methods of one class from another class, unless you access an instance of that class.
In your case, the code is embedded automatically into a run() method inside the Main class derived from groovy.lang.Script. The class MyClass is an inner class of the Main class. See here Scripts versus classes.
Solution: to access the method sayHello() of the Main class, you must pass an instance of it, using this keyword:
def sayHello() {
println "Hello"
}
class MyClass {
MyClass(Script host) {
host.sayHello()
}
}
def a = new MyClass(this)
Not sure what and why you are trying to do, but the simplest option to call a "function" from a constructor inside a Script is to put it in another class:
class A {
static sayHello() {
println "Hello"
}
}
class MyClass {
MyClass() {
A.sayHello()
}
}
def a = new MyClass()
I'm very new to Groovy.
Very simple question about the code found in CliBuilder.
http://docs.groovy-lang.org/latest/html/gapi/index.html?overview-summary.html
def cli = new CliBuilder(name:'ls')
cli.a('display all files')
cli.l('use a long listing format')
cli.t('sort by modification time')
def options = cli.parse(args)
assert options // would be null (false) on failure
assert options.arguments() == ['*.groovy']
assert options.a && options.l && options.t
The CliBuilder class behaves as knowing whatever methods we want to call in advance. By what Groovy's feature it can be supported?
This is called Runtime metaprogramming.
If you want to create your own class with "dynamic methods", the easiest way is to implement the GroovyInterceptable interface and add the invokeMethod method to your class.
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
'invokedMethod'
}
}
Whenever a method is called on an instance if the class Interception, invokeMethod is called instead. Note that this is also true for methods actually defined in the class (e.g. definedMethod)
You can use the metaClass to call the actual method like this
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
if (name == "actualMethod") {
return metaClass.invokeMethod(this, name, args)
}
return "invokedMethod: $name($args)"
}
def actualMethod() {
return 'hello there'
}
}
Here a call to actualMethod still goes through invokeMethod, however invokeMethod contains logic to call the actual method.
There are some other ways (see link on top) to acomplish similar behavior, but I found this to be the easiest.
Note that runtime metaprogramming is incompatible with #CompileStatic unless you add a TypeCheckingExtension to mitigate this.
Run Example
I have the following two Groovy classes:
Buzz.groovy:
import widgets.Fizz
class Buzz {
def WhistleFeather
def init = { servletContext ->
WhistleFeather.load()
println "WhistleFeather loaded."
}
def destroy = { }
}
WhistleFeather.groovy:
package net.me.myapp
import widgets.Fizz
public class WhistleFeather {
def navMenu
def load() {
println "Loading!"
}
}
When execution gets to the WhistleFeather.load() method call I'm getting a NullPointerException. Can anyone see why?
WhistleFeather#load is an instance method, not a static method. Either call it with new WhistleFeather().load(), or turn it into a static method (static load() { ... }).
I want to create a groovy class og script like this:
//...
def slurper = new ConfigSlurper().parse(someFile)
//...
//The exact method declaration
def methodCall(def arg){
//Whatever i want to do
}
//Maybe it is easier with methodMissing
def methodMissing(def args) {
//Whatever i want to do
}
The file to slurp could look like this:
some {
property = methodCall("with arg")
}
The question is how i can delegate the "methodCall" to the class or script that parses with the configslurper? At the moment it will give you a methodMissing.
I thik that this blog post have an example of what are you trying to do. It's more complicated than a methodMissing but can be done.
Thanks to Sérgio Michels link I found a solution:
public class ScriptWithMethods extends Script {
String scriptText;
public ScriptWithMethods(File file) {
scriptText = file.text
}
public void run() {
GroovyShell shell = new GroovyShell();
Closure closure = shell.evaluate("{it->$string}");
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = this
closure.call()
}
def methodCall(def arg){
//Whatever i want to do
}
}
//...
def script = new ScriptWithMethods(scriptText:someFile)
def slurper = new ConfigSlurper().parse(script)
Of cause you could also use "method missing", but this works in my usecase
At runtime I'm grabbing a list of method names on a class, and I want to invoke these methods. I understand how to get the first part done from here:
http://docs.codehaus.org/display/GROOVY/JN3535-Reflection
GroovyObject.methods.each{ println it.name }
What I can't seem to find information on is how to then invoke a method once I've grabbed its name.
What I want is to get here:
GroovyObject.methods.each{ GroovyObject.invokeMethod( it.name, argList) }
I can't seem to find the correct syntax. The above seems to assume I've overloaded the default invokeMethod for the GroovyObject class, which is NOT the direction I want to go.
Once you get a MetaMethod object from the metaclass, you can call invoke on it. For example:
class MyClass {
def myField = 'foo'
def myMethod(myArg) { println "$myField $myArg" }
}
test = new MyClass()
test.metaClass.methods.each { method ->
if (method.name == 'myMethod') {
method.invoke(test, 'bar')
}
}
Alternatively, you can use the name directly:
methodName = 'myMethod'
test."$methodName"('bar')
Groovy allows for dynamic method invocation as well as dynamic arguments using the spread operator:
def dynamicArgs = [1,2]
def groovy = new GroovyObject()
GroovyObject.methods.each{
groovy."$it.name"(staticArg, *dynamicArgs)
}
Reference here
Question answered here.