Groovy Copying / Combining MetaMethods From Multiple Objects - groovy

I have two classes. At runtime, I want to "clone" the methods of one object, over to another. Is this possible? My failed attempt using leftshift is shown below.
(Note: I also tried currMethod.clone() with the same result.)
class SandboxMetaMethod2 {
String speak(){
println 'bow wow'
}
}
class SandboxMetaMethod1{
void leftShift(Object sandbox2){
sandbox2.metaClass.getMethods().each{currMethod->
if(currMethod.name.contains("speak")){
this.speak()
this.metaClass."$currMethod.name" = currMethod
this.speak()
}
}
}
String speak(){
println 'woof'
}
}
class SandboxMetaMethodSpec extends Specification {
def "try this"(){
when:
def sandbox1 = new SandboxMetaMethod1()
def sandbox2 = new SandboxMetaMethod2()
sandbox1 << sandbox2
then:
true
}
}
//Output
woof
speak
woof
Per Request, I am adding background as to the goal / use case:
It's very much like a standard functional type of use case. In summary, we have a lot of methods on a class which applies to all of our client environments (50-100). We apply those to process data in a certain default order. Each of those methods may be overridden by client specific methods (if they exist with the same method name), and the idea was to use the approach above to "reconcile" the method set. Based on the client environment name, we need a way to dynamically override methods.
Note: Overriding methods on the metaclass is very standard (or should i say, it's the reason the amazing capability exists). And it works if my method exists as text like String currMethod = "{x-> x+1}", then i just say this.metaClass."$currMethodName" = currMethod. My challenge in this case is that my method is compiled and exists on another class, rather than being defined as text somewhere.
The goal of having all the custom methods compiled in client-specific classes at build time was to avoid the expense of compilation of these dynamic methods at runtime for each calculation, so all client-specific methods are compiled into a separate client-specific JAR at build time. This way also allows us to only deploy the client-specific code to the respective client, without all the other clients calculations in some master class.
I hope that makes sense.
New Approach, in Response to Jeremie B's suggestion:
Since I need to choose the trait to implement by name at runtime, will something like this work:
String clientName = "client1"
String clientSpeakTrait = "${clientName}Speak"
trait globalSpeak {
String speak() {
println 'bow wow'
}
}
trait client1Speak {
String speak() {
println 'woof'
}
}
def mySpeaker = new Object().withTraits globalSpeak, clientSpeakTrait

A basic example with Traits :
trait Speak {
String speak() {
println 'bow wow'
}
}
class MyClass {
}
def instance = new MyClass()
def extended = instance.withTraits Speak
extended.speak()
You can choose which trait to use at runtime :
def clientTrait = Speak
def sb = new Object().withTraits(clientTrait)
sb.speak()
And dynamically load the trait with a ClassLoader :
def clientTrait = this.class.classLoader.loadClass "my.package.${client}Speak"
def sb = new Object().withTraits(clientTrait)

Related

Why is Groovy metaClass .static changes using MOP not behaving as expected

I have set up a simple dummy class as follows, and used a static initialiser to update the metaClass:
class DynamicExtendableClass {
static String declaredStaticString = "declared static string"
static String getDeclaredMethodStaticString () {
"static method returning string"
}
static {
println "static initialiser - adding dynamic properties and methods to metaClass"
DynamicExtendableClass.metaClass.addedProperty = "added property to class metaClass"
DynamicExtendableClass.metaClass.getAddedMethod = { -> "added closure as method" }
DynamicExtendableClass.metaClass.static.getStaticAddedMethod = { -> "added closure as static method" }
}
}
I have a simple test case like this:
#Test
void testExtendedMetaClassStuff () {
DynamicExtendableClass testInstance = new DynamicExtendableClass()
assertEquals ("added property to class metaClass", testInstance.addedProperty)
assertEquals ("added closure as static method", testInstance.getStaticAddedMethod()) //calls getStaticAddedMethod - groovy trick
assertEquals ("added closure as method", testInstance.addedMethod) //works. calls getAddedMethod - groovy trick for getXxx as property
assertEquals ("added closure as static method", DynamicExtendableClass.staticAddedMethod ) //works class static class Closure
}
Which works only once you create a first instance of the class which forces a switch to ExpandoMetaClass for you.
If you don't do this first the default HandleMetaClassImpl doesn't work for this.
However to get this to work for static you have to create closure like getXxxx = {-> ...}, which if you call 'DynamicExtendableClass.staticAddedMethod' will sneakily invoke the closure for you.
However, there's not really a means to add a property capability here for '.static' as there is on the standard metaClass itself. All you can do is set a closure onto .static. Why is this?
The other problem is having to create an instance of the class first to force the switch to ExpandoMetaClass, is there not a simple way to force the metaClass change when declaring the class in the first class, before creating any instances ?
I want to add some static properties (later some methods maybe ) dynamically to a class, but all you can add is static closures, which is a little limiting on the scenario I had in mind.
PostScript
I managed to force a change of metaClass on class without having to create an instance, but it's a bit hard work:
#Test
void testMetaClassStatic () {
println DynamicExtendableClass.metaClass
MetaClassRegistry registry = GroovySystem.getMetaClassRegistry()
MetaClass origMC = registry.getMetaClass(DynamicExtendableClass)
assert origMC.getClass() == HandleMetaClass //default implementation
ExpandoMetaClass emc = new ExpandoMetaClass (DynamicExtendableClass, true, true)
emc.static.getStaticAddedMethod = {-> "static hello from my emc"}
emc.initialize()
registry.removeMetaClass(DynamicExtendableClass)
registry.setMetaClass(DynamicExtendableClass, emc)
assert DynamicExtendableClass.metaClass.getClass() == ExpandoMetaClass
assert DynamicExtendableClass.staticAddedMethod == "static hello from my emc"
registry.removeMetaClass(DynamicExtendableClass)
registry.setMetaClass(DynamicExtendableClass, origMC)
}
But doing this breaks my previously working tests (not sure why) with:
Could not initialize class extensible.DynamicExtendableClass
java.lang.NoClassDefFoundError: Could not initialize class extensible.DynamicExtendableClass
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:73)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:108)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:59)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:263)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:268)
at extensible.DynamicExtendableClassTest.testExtendedMetaClassStuff(DynamicExtendableClassTest.groovy:22)
at ...
Another postscript
I did a little exploration with a debugger. 1st the metaClass.static returns a class of type ExpandoMetaClass.ExpandoMetaProperty which of itself isn't terribly useful. You can do a direct .#this$0 field access however which just points the same metaClass instance as the target class you start with.
Therefore ignoring this you can do a direct field grab on <yourClass>.metaClass.#expandoProperties (I tried to get this via reflection using:
PropertyValue expandoProperties = clazz.metaClass.getMetaPropertyValues().find{it.name == 'expandoProperties'}
List<MetaBeanProperty> MBprops2= properties.getValue()
Map m2 = MBprops.findAll{Modifier.isPublic(it.modifiers)}.collectEntries{[(it.name), it.getProperty(clazz)] }
but it doesn't get the same content as the direct field access does.
The direct field access returns a Map where the key is the string value of any added closures or properties added dynamically to the metaClass, and the value is a MetaBeanProperty reference.
On that MetaBeanProperty you can invoke the getProperty (object) using with the class metaClass or per instance metaClass - and it returns the value of that property (whether it's just a closure or a real property) for you. You can also test whether its static or not:
Map m4 = thisMc.#expandoProperties
MetaBeanProperty asm = m4['addedStaticMethod']
def val2 = asm.getProperty(clazz)
boolean isstatic = Modifier.isStatic(asm.modifiers)
Kind of brutal but it sort of works if you want to dynamically query the dynamic editions to the metaclass.
The problem of forcing the switch from default metaClass to the ExpandoMetaClass remains a problem. The best way seems to create a throw away class instance as this does the one time switch for you.
I tried to force this myself using the metaClass registry which you can do, but then the future create new instance for your class seems to stop working ie. doing somethings like this and putting the original back afterwords seems to break any future new <MyClass>() calls.
MetaClassRegistry registry = GroovySystem.getMetaClassRegistry()
MetaClass origMC = registry.getMetaClass(DynamicExtendableClass)
assert origMC.getClass() == MetaClassImpl //default implementation
def constructors = MetaClassImpl.getConstructors()
ExpandoMetaClass emc = new ExpandoMetaClass (DynamicExtendableClass, true, true)
emc.static.getStaticAddedMethod = {-> "static hello from my emc"}
emc.constructor = { new DynamicExtendableClass() }
emc.initialize()
registry.removeMetaClass(DynamicExtendableClass)
registry.setMetaClass(DynamicExtendableClass, emc)
assert DynamicExtendableClass.metaClass.getClass() == ExpandoMetaClass
assert DynamicExtendableClass.staticAddedMethod == "static hello from my emc"
registry.removeMetaClass(DynamicExtendableClass)
registry.setMetaClass(DynamicExtendableClass, origMC)

Groovy - can a method defined in an Interface have default values?

If the following is entered in Eclipse/STS (with groovy):
interface iFaceWithAnIssue {
def thisIsFine(a,b,c)
def thisHasProblems(alpha='va')
}
The only line that complains is the one trying to use a default value. I can not tell from the codehaus site if this is supported or not.
The IDE error is:
Groovy:Cannot specify default value for method parameter
So this makes me think it is not supported. As there will be multiple implementations, I wanted to use an interface here. I don't really need the default value in the interface, but there is an error trying to fulfill the interface contract if the implementation class then tries to default this argument. Is there any way?
No, you cannot.
When you define a default value, Groovy actually creates multiple methods in your class, so for example:
class Test {
void something( a=false ) {
println a
}
}
Actually creates
public void something(java.lang.Object a) {
this.println(a)
}
and
public void something() {
this.something(((false) as java.lang.Object))
}
This can't be done as it stands in Interfaces.
You could do:
interface iFaceWithAnIssue {
def thisHasProblems()
def thisHasProblems(alpha)
}
Then
class Test implements iFaceWithAnIssue {
// This covers both Inteface methods
def thisHasProblems(alpha='va') {
// do something
}
}

Groovy metaClass closures vs dynamic mixins

So I want to add methods to JDK classes like InputStream, File, etc. I'm trying to figure out what is the best way to do that, but it seems there are several options for doing it. One way is do this by adding methods into the metaClass property on the Class like so:
InputStream.metaClass.copy = { OutputStream out ->
long total = 0
byte[] buffer = new byte[8096]
int len
while ((len = read(buffer)) >= 0) {
out.write(buffer, 0, len)
total += len
}
out.flush()
return delegate
}
Another way is using dynamic mixins like this:
class EnhancedInputStream {
static {
InputStream.metaClass.mixin( EnhancedInputStream )
}
public InputStream copy( OutputStream out ) {
long total = 0
byte[] buffer = new byte[8096]
int len
while ((len = mixinOwner.read(buffer)) >= 0) {
out.write(buffer, 0, len)
total += len
}
out.flush()
return mixinOwner
}
}
So the first question is do dynamic Mixins replace the use of using metaClass + Closure to create mixins? The examples of dynamic mixins don't really discuss scoping rules in any detail that I can find. Which leads me to the next point.
You can see in the first code sample using metaClass I used delegate to get access to the this pointer of the class I was adding methods to. What is the equivalent way to do that using dynamic Mixins? All examples I've found are stateless (pointless really). I found one example mentioning a special member mixinOwner that could be used in place of delegate. Is that true?
Second you'll see I used a static block in EnhancedInputStream to add the mixin dynamically to InputStream. When using metaClass what is the best way to add those? Another static block with import statement?
I suppose I really want just a compile time Mixin where I can define the #Mixin on the source of the mixin instead of destination because I didn't write the destination. Like
#MixinInto(File)
public class EnhancedFileMixin {
public void zip( File output ) {
// .....
}
}
But that doesn't appear to exist in Groovy land. So what's the best approach to reach this using metaClass or dynamic mixins?
I guess the nearest to #MixinInto would be the magic package convention. I couldn't mix it into a interface, but i managed to mix it into a FileInputStream, if that suits your case. I guess you can add state using the MetaClass which comes in the constructor.
To write a class to be mixed into InputStream. It needs to be:
In the package groovy.runtime.metaclass.java.io
Named FileInputStreamMetaClass (exactly)
Compiled and put into the classpath
Extend DelegatingMetaClass
It can only intercept the GroovyObject methods, so it is not so straightforward. If you are in for a pure dynamic groovy, it is great:
package groovy.runtime.metaclass.java.io
class FileInputStreamMetaClass extends DelegatingMetaClass {
FileInputStreamMetaClass(MetaClass meta) {
super(meta)
println "built FileInputStreamMetaClass"
}
Object invokeMethod(Object delegate, String method, Object[] args) {
switch (method) {
case "copy":
return "i'm copying stuff"
default:
return super.invokeMethod(delegate, method, args)
}
}
}
Compiling:
$ groovyc FileInputStreamMetaClass.groovy
$ groovy -cp . InputTest.groovy
A test:
InputStream input = new FileInputStream("/tmp/test.tmp")
assert input.copy() == "i'm copying stuff"
A bit cumbersome.
I'd go for Extensions any time of the day. Three files:
// file META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
moduleName=InputExtensionModule
moduleVersion=0.1
extensionClasses=InputStreamExtension
The extension:
class InputStreamExtension {
static String copy(InputStream input) {
"copying stuff, doc"
}
}
The test:
def input = new FileInputStream("/tmp/test.tmp")
assert input.copy() == "copying stuff, doc"
Compile and run:
$ groovyc InputStreamExtension.groovy
$ groovy ISExtensionTest.groovy
And i think the extension is the perfect place to use the static { mixin } block. With some changes:
class InputStreamExtension {
static {
InputStream.mixin InputStreamMixin
}
static String copy(InputStream input) { "copying stuff, doc" }
}
#Category(InputStream)
class InputStreamMixin {
Object pop() {
"input mixin pop"
}
}
A new test:
def input = new FileInputStream("/tmp/test.tmp")
assert input.copy() == "copying stuff, doc"
assert input.pop() == "input mixin pop"
Well I finally figured it out on my own. Essentially the this reference refers to the instance of the Mixin which doesn't do us much good. However, you can use the "as" keyword to convert that to the instance of the target class. For example:
class MyMixin {
static {
File mixin MyMixin
}
File foo() {
return this as File
}
}
File f = new File()
println( f.foo().equals( f ) )
As for mixinOwner and owner references that the jira bug refers to. They don't exist. This is the only way to get a reference to the instance that the mixin was added to.
I wrote up a longer blogpost about it because I thought this was important information for future Groovy programmers since there is zero official docs discussing this.
http://wrongnotes.blogspot.com/2013/06/groovy-mixins-and-this-pointer.html
I am glad you asked this question. To answer a very important question:
I suppose I really want just a compile time Mixin where I can define the #Mixin on the source of the mixin instead of destination because I didn't write the destination.
You cannot achieve this by #Mixin but we do have something in Groovy which will help you out. It is called #Category. Let me go through your example again to show you how you can actually effectively use this in category. Have a look at the below script:
#Category(InputStream)
class InputStreamCategory{
def copy(OutputStream out){
long total = 0
byte[] buffer = new byte[8096]
int len
while ((len = this.read(buffer)) >= 0) {
out.write(buffer, 0, len)
total += len
}
out.flush()
return this
}
}
class MyUtil{
def str = 'This is a dummy String!!!!'
InputStream inputS = new ByteArrayInputStream(str.bytes)
OutputStream outputS = new ByteArrayOutputStream()
def copy(){
use(InputStreamCategory){
inputS.copy(outputS)
println "Printing Output Stream: " + outputS
}
}
}
def util = new MyUtil()
util.copy()
//Prints:
Printing Output Stream: This is a dummy String!!!!
Explanation:-
#Category(InputStream) sets the this in InputStreamCategory and in your util class you just use the newly added method copy to InputStream. The benefit for using category is that you get hold of the caller object in this case inputS. The first parameter passed into a category always refers to the caller. You can have different categories for different implementations like FileCategory etc and then create an Utility Class to use those Categories. Therefore, you would end up with utilities like zip, copy, etc.
You could get detail information about the same from the api. I also highly recommend going through Category and Mixin Transformations.
To answer the first question:-
do dynamic Mixins replace the use of using metaClass + Closure to create mixins?
No they do not. metaClass implementation does not create a Mixin. It just adds another method in the metaData registry about the class while runtime. You get an handle to the delegate. On the other hand #Mixin gives you the ability to inherit pre-defined properties.

Groovy adding code to a constructor

Is there a way in Groovy that I can add code to a constructor when a class is instantiated? I have a Groovy class (but I can't modify the source of this particular one), but I was hoping there was a way to inject code (maybe via the metaclass) so my code gets run as part of the constructor (in this case there is only one, default constructor).
Thanks,
Jeff
You can override the constructor, but it's a little tricky, particularly if you're overriding the default constructor. You need to assign a closure to the class's metaClass.constructor, and the closure should return a new instance. The tricky part is that if you call the constructor you've overriden, you'll get into a recursive loop and generate a stack overflow. You need another way to get an instance of the class, such as a different constructor.
For testing, it's sometimes possible to get around this limitation. Usually, it's enough to first instantiate an object, then override the constructor to return the existing instance. Example:
class MyObject {
String something
MyObject() { something = "initialized" }
}
testInstance = new MyObject()
testInstance.something = "overriden"
MyObject.metaClass.constructor = { -> testInstance }
aNewObject = new MyObject()
assert aNewObject.is(testInstance)
assert aNewObject.something == "overriden"
It is possible to add new constructors or replace the old one. If you need the original constructor, you can use reflection for that:
MyObject.metaClass.constructor = { -> // for the no-arg ctor
// use reflection to get the original constructor
def constructor = MyObject.class.getConstructor()
// create the new instance
def instance = constructor.newInstance()
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
Note that you have to change this if you have parameters to your constructors, e.g:
// Note that the closure contains the signature of the constructor
MyObject.metaClass.constructor = { int year, String reason ->
def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class)
def instance = constructor.newInstance(
2014, "Boy, am I really answering a question three years old?")
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
PS: Note that when you want to add constructors which are not yet existent, use the << operator instead: MyObject.metaClass.constructor << { /* as above */ }.
You can bypass the limitations in the solution proposed by storing the original constructor using standard Java reflection. For example, this is what I do initialize a class (basic injection) in a spock test:
def setupSpec() {
MockPlexusContainer mockPlexusContainer = new MockPlexusContainer()
def oldConstructor = MY_CLASS.constructors[0]
MY_CLASS.metaClass.constructor = { ->
def mojo = oldConstructor.newInstance()
mockPlexusContainer.initializeContext(mojo)
return mojo
}
}
This gets invoked only once, but eveytime someone calls a constructor I get a different instance avoiding cleaning values and ensuring thread safety.

Groovy :: #Mixin methods override target class methods

class A {
def test() { println "parent" }
}
#Mixin(A)
class B {
def test() { println "child" }
}
new B().test() // prints "parent", but I am expecting it to print "child"
This looks like some kind of reverse inheritance.
Are mixins only to be used as a means to define new methods?
I can of course use conventional inheritance and go with extends, but the use case entails a form builder where each domain has a unique form implementation and I'd like to, in my application controller, catch form requests and do a MyUniqueDomainForm.mixin DefaultFormMethods (so I only need to define default methods when I need to, as well as not having to import my.package.app.DefaultFormMethods in each form class)
Whatever you mixin will overload whatever is already there...
In this example, at compile time B.test() overloads the inherited A.test() method
But then at runtime, A.test() is added via the mixin, which re-overloads the previously overloaded method
If it was not this way round you would not be able to alter the existing characteristics of a class using mixins
ie (this is a silly example, but I believe it gets my point across):
class AddNotMinus {
static def minus( int a, int b ) {
a + b
}
}
Integer.mixin AddNotMinus
println 10 - 10
prints 20

Resources