Trying to call a function from inside the class in Groovy, getting MissingMethodException - groovy

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()

Related

Handle function calls on a class in Node.JS

Assuming that you have a class
class MyClass {
world() {
console.log("hello world");
}
}
I can run the method similar to the following:
var hello = new MyClass();
hello.world();
# outputs: hello world
Is there a way to handle direct function calls on an object? For example:
hello();
Returns: TypeError: hello is not a function.
Can I make this call a default function? For example, similar to PHP's invoke function ...
We can only make something callable in JavaScript if that thing is an object which, at some point, delegates to Function.prototype. Therefore, our class will need to extend Function or extend from a class which extends Function. We also need to be able to access instance variables from our class object (in order to call invoke()), so it needs to be bound to itself. This binding can only happen in the constructor.
Since our class will inherit from Function, we need to call super before being able to use this . However, the Function constructor actually takes a code string, which we won't have, because we want to be able to set invoke later on. So we'll need to extend Function in a different class which will be the parent class to our class and which will do the work of setting the prototype of our dummy function (which we need in order to be able to call the returned object). Bringing all of this together, we get:
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class MyClass extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
invoke() {
console.log("Hello, world!");
}
}
x = new MyClass();
x(); //prints "Hello, world!"
I mostly adapted the techniques found in this answer in order to do this.
An interesting aspect of using this technique is that you could name MyClass something like Callable and remove the invoke method - then any class which extends Callable would become callable as long as it had an invoke() method. In fact...
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Callable extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
}
class CallableHello extends Callable {
invoke() {
console.log("Hello, world!");
}
}
class CallableBye extends Callable {
invoke() {
console.log("Goodbye cruel world!");
}
}
x = new CallableHello();
x(); //prints "Hello, world!"
y = new CallableBye();
y(); //prints "Goodbye cruel world!"
(Of course, you could get the same effect by setting properties on function objects, but this is more consistent I guess)

access global variable in static scope

Is there a way to access global variable, declared in the script, from the static method of the class, declared in the same script?
For example
def s = "12345"
class MyClass {
static def method() {
println s
}
}
Because that way it fails with the error
You attempted to reference a variable in the binding or an instance variable from a static context
which is expected though.
There is a related discussion at this question:
Groovy scope - how to access script variable in a method
Related in that both questions refer to using a global variable within a class, but this question differs somewhat in that you are seeking to use a static method which alters how you pass the script instance or binding (2 choices).
Passing the Script's Instance
import groovy.transform.Field
#Field def s = "12345"
class MyClass {
static def method(si) {
return si.s
}
}
assert MyClass.method(this) == "12345"
Passing the Script's binding
s = "12345" // NOTE: no 'def'
class MyClass {
static def method(b) {
return b.s
}
}
assert MyClass.method(binding) == "12345"
Well, the problem is that in Groovy there is no such thing as a global variable. What is loosely considered a global variable is actually a static property within some class.
For example, if you remove the println line so that the code compiles, you get something like this out of the compiler:
public class script1455567284805 extends groovy.lang.Script {
...
public java.lang.Object run() {
return java.lang.Object s = '12345'
}
...
}
public class MyClass implements groovy.lang.GroovyObject extends java.lang.Object {
...
public static java.lang.Object method() {
// This is where the println would have been.
return null
}
...
}
As you can see, an additional class is created and the the s variable is declared within the method run() of that class. This makes the variable inaccessible to your other class.
Note: Removing the def will not address this issue.
Solution
Your best bet is to place your "global variables" into a class, possibly as static properties, like this:
class Global {
static Object S = "12345"
}
class MyClass {
static def method() {
println Global.S
}
}
You included a variable type with the s variable (by using the def type). In a Groovy script, this is treated as a local variable - and local to the run() method that is generated - which is kind of like a main() class. As a result, the variable is not available in other methods or classes.
If you remove the def you will be able to make use of the s variable.
Here is the Groovy documentation that explains this further.

NullPointerException when calling a method on another Groovy class

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() { ... }).

Load groovy classes/scripts dynamically without compilation?

I have a set of groovy scripts in package hierarchy. I have 1 main script, from which I want to call others. For example I have these scripts (with public classes/interfaces of the same name in them):
package.MainScript
package.MyInterface;
package.utils.MyInterfaceImpl1 //implements MyInterface
package.utils.MyInterfaceImpl2 //implements MyInterface
Is there a way to call one script from the other without knowing called class name at compile time? I mean to do something like dynamic class loading like:
class MainScript {
public static void main (String[] args) {
MyInterface instance = Class.forName("package.utils.Util1");
}
}
Yeah! Groovy is a dynamic language. You can create class instance dynamically.
package.MyInterface
class MyInterfaceImpl1 {
def greet() {
"Hello"
}
}
package.MyInterface
class MyInterfaceImpl2 {
def greet() {
"Hi!"
}
}
def name = 'MyInterfaceImpl1' // Choose whatever you want at runtime
def className = Class.forName("MyInterface.$name")
def instance = className.newInstance()
assert instance.greet() == 'Hello'

Groovy Prototype Object

I have a method with an incoming variable, which represents a script.
e.g.
hello.groovy
Foo.init(this)
Foo.groovy
class Foo {
static init(app) {
}
}
What is the best way to add a ton of new functionality to the app variable in the init method? Basically, I would like to add all the functionality of another object to the app object.
For instance, if I had another class:
class Bar {
def a() { }
def b() {
}
}
I would like the app object to basically be a new Bar(). In JavaScript, this is easy by using the prototype object, but I cannot seem to get it working in groovy. What is the best way to accomplish this? Or should I be doing something differently?
YourClass.metaClass.static.yourMethod is the most similar to JS prototype I've seen in Groovy. Check this link out:
Groovy meta-programming - adding static methods to Object.metaClass
Cheers.
There are several ways to do this and each has advantages and disadvantages. On the Groovy Documentation page, the section on Dynamic Groovy illustrates several of these. If I understand you correctly, the simplest way is to just use the metaClass of an instance to add new functionality, a la:
class Foo {
static void init (a) {
a.metaClass.a = { println "a()"; }
a.metaClass.b = { println "b()"; }
}
}
def myObject = new Object();
Foo.init (myObject);
myObject.a();
myObject.b();
The easiest way to do this would be with a mixin. Basically you can call mixin on app's class and pass it another class to incorporate that functionality into it.
I've modified your example to show this mixing in the Bar class.
class Foo {
static init(app) {
app.class.mixin Bar
}
}
class Bar {
def a() { println "a called" }
def b() {
println "b called"
}
}
def app = new Object()
Foo.init(app)
app.a()
app.b()
The output of this would be:
a called
b called
In this case I added Bar to the Object class but you could add it to any class in your application.

Resources