Reputation: 574
I'm trying to generate classes dynamically in Groovy. My approach is this:
class MetaClassTest {
static class TestClass {
String getName() {
return "Jake"
}
}
public static void main(String[] args) {
def testClass = TestClass
def metaMethod = testClass.metaClass.getMetaMethod('getName', [] as Class[])
testClass.metaClass.getName = {
metaMethod.invoke(delegate) + " and the Fatman"
}
assert testClass.newInstance().name == "Jake and the Fatman"
}
}
This however changes the behavior of the original class which is what I don't want. So my question is:
How can I clone (and probably rename) an existing class dynamically so that I'd be able to create multiple derivates?
Upvotes: 0
Views: 969
Reputation: 574
The most transparent (even though still dirty) solution so far has been already hinted here. I can create the child class skeleton using the GroovyClassLoader.parse()
method and then enrich it via metaClass
.
class TestClass {
String getName() {
return "Jake"
}
}
def parentClass = TestClass
def groovyClassLoader = new GroovyClassLoader(parentClass.classLoader)
def childClass1 = groovyClassLoader.parseClass("class ChildClass1 extends ${ parentClass.canonicalName } {}")
def oldGetName1 = childClass1.metaClass.getMetaMethod('getName', [] as Class[])
childClass1.metaClass.getName = {
oldGetName1.invoke(delegate) + " and the Fatman"
}
def childClass2 = groovyClassLoader.parseClass("class ChildClass2 extends ${ parentClass.canonicalName } {}")
def oldGetName2 = childClass2.metaClass.getMetaMethod('getName', [] as Class[])
childClass2.metaClass.getName = {
oldGetName2.invoke(delegate) + " the Dog"
}
assert childClass1.newInstance().name == "Jake and the Fatman"
assert childClass2.newInstance().name == "Jake the Dog"
My reason to create classes dynamically at runtime is that the application can be extended using Groovy DSL scripts written by people with hardly any programming skills in general.
Upvotes: 0
Reputation: 3016
You may override class instance methods:
import groovy.transform.AutoClone
@AutoClone
class TestClass {
String getName() {
return "Jake"
}
}
def tc1 = new TestClass()
def tc2 = tc1.clone()
tc1.metaClass.getName = {'Fatman'}
tc2.metaClass.getName = {'Joe'}
assert tc1.getName() == 'Fatman'
assert tc2.getName() == 'Joe'
assert new TestClass().getName() == 'Jake'
Upvotes: 1
Reputation: 96
I'm not sure if the following works, but it may be worth a try: Can you check if you can somehow deep-copy the TestClass and then modify the only the cloned class? The folllowing might come in handy:
Use autoclone
And maybe the groovy lang metaprogramming to look for more on metaprogramming.
Upvotes: 0