ExpandoMetaClass - Static Methods + singleton + overloaded functions - groovy

Using ExpandoMetaClass Static Methods can be added dynamically, how can i use this ExpandoMetaClass in Singleton object, with overloaded static function in it, let say the sample program need to be re written using ExpandoMetaClass whats needs to changed in the below program
#Singleton
class testA {
def static zMap = [:]
static def X() {
Y()
}
static def Y() {
}
static def X(def var) {
Y(var)
}
static def Y(def var) {
zMap.put(var)
}
}

One of the reasons to use a singleton is to avoid having static state and methods in a class. If you're using #Singleton, there's no reason to have static methods or fields. The way to use a singleton is like this:
#Singleton class TestA {
def someField = "hello"
def methodX() {
someField
}
}
println TestA.instance.methodX()
You can extend the singleton using ExpandoMetaClass like so:
TestA.instance.metaClass.newMethod = { -> "foo" }
TestA.instance.metaClass.methodX = { -> "goodbye" }
println TestA.instance.newMethod()
println TestA.instance.methodX()
If you really want a static method, you can do something like this:
TestA.metaClass.static.methodY = { -> "I am static" }
println TestA.methodY()
Note that if you override the class metaClass, rather than the instance metaClass, it won't apply to the instance if the instance has already been created. To get around this use #Singleton(lazy = true) and override the metaClass before accessing the instance.

Related

How can we replace a interface method in groovy?

Question
How can I overwrite a method in Groovy if the class implements an interface? If the class does not implement an interface I can overwrite the method, but if the class implements an interface the method does not overwrite.
Example without implement
interface IA {
void abc()
}
class A {
void abc() {
println "original"
}
}
x= new A()
x.abc()
x.metaClass.abc = {-> println "new" }
x.abc()
The output of this is
original
new
Example with implement
Consider the following example where class A implements interface IA
interface IA {
void abc()
}
class A implements IA {
void abc() {
println "original"
}
}
x= new A()
x.abc()
x.metaClass.abc = {-> println "new" }
x.abc()
The output in this case is
original
original
As mentioned in the comments, looks like this is a pretty embarrassing bug, unfortunately.
But depending on your actual scenario, it may be possible to work around the problem.
Use Groovy #Category
If you can control where the method will be called, then you can use a Groovy Category to replace the method within a block:
x= new A()
x.abc()
#Category(A)
class ReplaceAbc {
void abc() {
println 'new'
}
}
use(ReplaceAbc) {
x.abc()
}
Replace the instance with an anonymous sub-type of the original type
If you can re-assign the variable, then this is an obvious way to override the method:
x= new A()
x.abc()
x = new A() {
#Override
void abc() {
println 'new'
}
}
x.abc()
How can I overwrite a method in Groovy if the class implements an
interface?
There are a few ways to do it. One is with runtime extension methods.
See the project at github.com/jeffbrown/victorchoymetaprogramminginterface.
lib/src/main/groovy/victorchoymetaprogramminginterface/IA.groovy
package victorchoymetaprogramminginterface
interface IA {
String abc()
}
lib/src/main/groovy/victorchoymetaprogramminginterface/A.groovy
package victorchoymetaprogramminginterface
class A implements IA{
#Override
String abc() {
'A.abc'
}
}
lib/src/main/groovy/victorchoymetaprogramminginterface/extensions/SomeInterfaceExtensionMethods.groovy
package victorchoymetaprogramminginterface.extensions
import victorchoymetaprogramminginterface.IA
class SomeInterfaceExtensionMethods {
static String abc(IA ia) {
'SomeInterfaceExtensionMethods.abc'
}
}
lib/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
moduleVersion=1.0
moduleName=Demo Extensions
staticExtensionClasses=victorchoymetaprogramminginterface.extensions.SomeInterfaceExtensionMethods
The following test passes:
lib/src/test/groovy/victorchoymetaprogramminginterface/TestInterfaceExtensions.groovy
package victorchoymetaprogramminginterface
import spock.lang.Specification
class TestInterfaceExtensions extends Specification {
def "test interface extensions"() {
setup:
def obj = new A()
expect:
obj.abc() == 'SomeInterfaceExtensionMethods.abc'
}
}

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.

Method aliasing in class with Groovy

I'm going to internationalize groovy API abit.
For final class (e.g. String)
String.metaClass.вСтроку = {-> this.toString() }
However, this will create additional closure. Isn't there any way to just alias method with another method?
Something like this:
String.metaClass.вСтроку = String.metaClass.&toString
You could use #Category transform like this
#Category(String) class StringInternationalization {
String вСтроку() {
this.toString()
}
int длина() {
this.length()
}
}
class ApplyMixin {
static {
String.mixin(StringInternationalization)
final helloString = "Привет мир!"
println helloString.вСтроку()
assert helloString.длина() == helloString.length()
}
}
new Main()
This will create 1 Category class for each localised class and one class to apply all mixin transformations(to register all methods.) Also should be faster, then individual closures.
More reading here: http://groovy.codehaus.org/Category+and+Mixin+transformations

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 methodMissing

I have a closure within an object Foo and inside the closure i define a method called 'myStaticMethod' that I want to resolve once the closure is called outside the object Foo. I also happen to have 'on purpose' a static method within my object Foo with the same name. When I call the closure i set the 'resolve strategy' to DELEGATE_ONLY to intercept the call to myStaticMethod that is defined within the closure.
I tried to achieve that through missingMethod but the method is never intercepted. When i make the Foo.myStaticMethod non static, the method is intercepted. I don't quite understand why this is happening though my resolve strategy is set to DELEGATE_ONLY. having the Foo.myStaticMethod static or not shouldn't matter or I am missing something
class Foo {
static myclosure = {
myStaticMethod()
}
static def myStaticMethod() {}
}
class FooTest {
def c = Foo.myclosure
c.resolveStrategy = Closure.DELEGATE_ONLY
c.call()
def missingMethod(String name, def args) {
println $name
}
}
To solve the problem, I ended up overriding the invokeMethod right before calling the closure in FooTests
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "Static Builder processing $name "
}
While trying to solve this problem, i discovered a very weird way to intercept missing static methods. Might be useful to some of you in the future.
static $static_methodMissing(String name, args) {
println "Missing static $name"
}
-Ken
Static methods unfortunately aren't intercepted by the closure property resolution. The only way that I know to intercept those is to override the static metaClass invokeMethod on the class that owns the closure, ex:
class Foo {
static myclosure = {
myStaticMethod()
}
static myStaticMethod() {
return false
}
}
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "in static invokeMethod for $name"
return true
}
def closure = Foo.myclosure
assert true == closure()

Resources