Create a new class "on the fly"? - groovy

... specifically in Groovy (hence tag)?
In Java you can't do this... but in dynamic languages (e.g. Python) you typically can.
An attempt to do something like in the given block of a Spock feature (i.e. test method) meets with, in Eclipse:
Groovy:Class definition not expected here. Please define the class at
an appropriate place or perhaps try using a block/Closure instead.
... an "appropriate" place would obviously be outside the feature. This would be clunky and not groovy. Having used Groovy for a few months now I get a feel for when Groovy should offer something groovier.
So say I'd like to extend my abstract class AbstractFoo and make a new subclass Foo, in my feature, is there any way to "use a block/Closure" to achieve something like that?

You can simply create an anonymous class by instantiating AbstractFoo and providing inline implementation of abstract methods. Consider following example:
abstract class AbstractFoo {
void bar() {
println text()
}
abstract String text()
}
def foo1 = new AbstractFoo() {
#Override
String text() {
return "Hello, world!"
}
}
def foo2 = new AbstractFoo() {
#Override
String text() {
return "Lorem ipsum dolor sit amet"
}
}
foo1.bar()
foo2.bar()
Both foo1 and foo2 implement AbstractFoo and they provide different implementation of text() method that results in different bar() method behavior. Running this Groovy script produces following output to the console:
Hello, world!
Lorem ipsum dolor sit amet
It's nothing Groovy-specific, you can achieve exactly the same behavior with Java. However you can make it a little bit more "groovier" by casting a closure to a AbstractFoo class, something like this:
def foo3 = { "test 123" } as AbstractFoo
foo3.bar()
In this case closure that returns "test 123" provides an implementation for an abstract text() method. It works like that if your abstract class has only single abstract method.
Abstract class with multiple abstract methods
But what happens if an abstract class has multiple abstract methods we want to implement on fly? In this case we can provide implementation of this methods as a map, where keys are names of abstract methods and values are closures providing implementation. Let's take a look at following example:
abstract class AbstractFoo {
abstract String text()
abstract int number()
void bar() {
println "text: ${text()}, number: ${number()}"
}
}
def foo = [
text: { "test 1" },
number: { 23 }
] as AbstractFoo
foo.bar()
This example uses an abstract class with two abstract methods. We can instantiate this class by casting a map of type Map<String, Closure<?>> to AbstractFoo class. Running this example produces following output to the console:
text: test 1, number: 23
Creating non-anonymous classes on fly in Groovy
Groovy also allows you to create a class e.g. from a multiline string using GroovyClassLoader.parseClass(input) method. Let's take a look at following example:
abstract class AbstractFoo {
void bar() {
println text()
}
abstract String text()
}
def newClassDefinitionAsString = '''
class Foo extends AbstractFoo {
String text() {
return "test"
}
}
'''
def clazz = new GroovyClassLoader(getClass().getClassLoader()).parseClass(newClassDefinitionAsString)
def foo = ((AbstractFoo) clazz.newInstance())
foo.bar()
Here we are defining a non-anonymous class called Foo that extends AbstractFoo and provides a definition of test() method. This approach is pretty error prone, because you define a new class as String, so forget about any IDE support in catching errors and warnings.
Providing a subclass in a test specification
Your initial question mentioned about an attempt to create a class for a specification in a given: Spock block. I would strongly suggest using the simplest available tool - creating a nested private static class so you can easily access it inside your test and you don't expose it outside the test. Something like this:
class MySpec extends Specification {
def "should do something"() {
given:
Class<?> clazz = Foo.class
when:
//....
then:
///....
}
private static class Foo extends AbstractFoo {
}
}

Related

How to reference subclass from a static superclass method in Groovy

A simplified version of what I'm trying to do in Groovy:
class Animal {
static def echo() {
println this.name // ie "class.name"
}
}
class Dog extends Animal {
}
class Cat extends Animal {
}
Dog.echo()
Cat.echo()
// Output:
// => Animal
// => Animal
//
// What I want:
// => Dog
// => Cat
I think what I'm asking here is: when I call a static method on an object, and
the static method is defined in the object's superclass, is there a way to obtain
the actual type of the object?
A static method is not defined in the object context, but in the class context. You might get confused by the presence of this in the Groovy static method. However, it's only a syntactic sugar that eventually replaces this.name with Animal.class.name.
If you compile the Animal class from your example with a static compilation enabled, you will see that it compiles to the following Java equivalent (result after decompiling the .class file):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
public class Animal implements GroovyObject {
public Animal() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public static Object echo() {
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
return null;
}
}
You can see that the following line in the echo method:
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
operates directly on the Animal class name. So from the echo method perspective, it doesn't matter how many classes extend it. As long as those classes invoke echo method defined in the Animal class, you will always see Animal printed as a result.
And there is even more than that. If you use the following compiler configuration script:
config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
and then compile the script (let's call it script.groovy) using this configuration option with the following command:
groovyc --configscript=config.groovy script.groovy
then you will see something like this after decompiling the .class file:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import org.codehaus.groovy.runtime.InvokerHelper;
public class script extends groovy.lang.Script {
public script() {
}
public script(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.runScript(script.class, args);
}
public Object run() {
Animal.echo();
return Animal.echo();
}
}
You can see that even though you have invoked Dog.echo() and Cat.echo() in your Groovy script, the compiler replaced these calls with the double Animal.echo() invocation. It happened because calling this static method on any other subclass does not make any difference.
Possible solution: applying double dispatch
There is one way to get the expected output - override echo static method in Dog and Cat class. I can assume that your real method may do something more than the exemplary echo method you have shown above, so you might need to call the super echo method from a parent class. But... there are two problems: (1) you can't use super.echo() in the static context, and (2) it doesn't solve the problem, because parent method still operates in the Animal class context.'
To solve this kind of issue you might want to mimic a technique called double dispatch. In short - when we don't have information about the caller in the method that was called, let's allow the caller to pass this information with the method call. Consider the following example:
import groovy.transform.CompileStatic
#CompileStatic
class Animal {
// This is a replacement for the previous echo() method - this one knows the animal type from a parameter
protected static void echo(Class<? extends Animal> clazz) {
println clazz.name
}
static void echo() {
echo(Animal)
}
}
#CompileStatic
class Dog extends Animal {
static void echo() {
echo(Dog)
}
}
#CompileStatic
class Cat extends Animal {
static void echo() {
echo(Cat)
}
}
Animal.echo()
Dog.echo()
Cat.echo()
This may sound like a boilerplate solution - it requires implementing echo method in each subclass. However, it encapsulates the echo logic in the method that requires Class<? extends Animal> parameter, so we can let every subclass to introduce their concrete subtype. Of course, this is not a perfect solution. It requires implementing echo method in each subclass, but there is no other alternative way. Another problem is that it doesn't stop you from calling Dog.echo(Animal) which will cause the same effect as calling Animal.echo(). This double dispatch like approach is more like introducing a shorthand version of echo method which uses the common static echo method implementation for simplicity.
I don't know if this kind of approach solves your problem, but maybe it will help you find a final solution.

groovy immutable object with parent class

I have two immutable groovy classes that have a few shared values that I'm trying to abstract to a parent class. However when I create the following, the second test case always fails. Although everything compiles correctly and no error is thrown at runtime, when I assign the parent property int he constructor, it is never set, resulting in a null value. I havent found any documentation that forbids this, but I'm wondering is this even possible? I've tried a number of configuration of Annotations and class-types (e.g. removing abstract from the parent) but nothing seems to work short of just removing the #Immutable tag altogether.
abstract class TestParent {
String parentProperty1
}
#ToString(includeNames = true)
#Immutable
class TestChild extends TestParent {
String childProperty1
String childProperty2
}
class TestCase {
#Test
void TestOne() {
TestChild testChild = new TestChild(
childProperty1: "childOne",
childProperty2: "childTwo",
parentProperty1: "parentOne"
)
assert testChild
assert testChild.parentProperty1
}
}
Based on the code for the ImmutableASTTransformation, the Map-arg constructor added by the createConstructorMapCommon method does not include a call to super(args) in the method body.
which means that immutable classes are self contained by default
Now if you want to do it you need to use composition instead of inheritance and this is an example of how you can do it :
import groovy.transform.*
#TupleConstructor
class A {
String a
}
#Immutable(knownImmutableClasses=[A])
class B {
#Delegate A base
String b
}
def b = new B(base: new A("a"), b: "b")
assert b.a
i hope this will help :)

Groovy, convenient print signatures for methods with arguments

I have some Groovy class, for example:
class Apple {
public void methodA(String myParam) {}
public void methodB(String myParam2, String myParam3) {}
}
And I want to print all methods of class Apple in convenient format, for example:
Class Apple:
- methodA <String: myParam>
- methodB <String: myParam2> <String: myParam3>
or just:
Class Apple:
- methodA <myParam>
- methodB <myParam2> <myParam3>
Is it possible in Groovy?
For now I'm using for-each loop for Apple.metaClass.methods and printing method.name, for example:
for (MetaMethod metaMethod in Apple.metaClass.methods) {
println metaMethod.name
}
But I can't find a way to print names of arguments..
Also, is it possible to know if there are default values for the arguments?
Could you please advise?
No(*). Parameter names are not stored with the bytecode (I believe they might be if the class is compiled with debugging turned on, but I've not tried it).
(* it is possible with some non-reflection digging, but it relies on a lot of things, and feels like it would be quite a brittle point in your design)
With Java 7 and below, you can just get the types of the arguments. With Java 8, a new getParameters call was added to java.lang.reflect.Method, so with Java 8 and Groovy 2.3+ it's possible to do:
class Apple {
public void methodA(String myParam) {}
public void methodB(String myParam2, String myParam3) {}
}
Apple.class.declaredMethods
.findAll { !it.synthetic }
.each { println "$it.name $it.parameters.name" }
To print:
methodB : [arg0, arg1]
methodA : [arg0]
But as you can see, the original parameter names are again lost.
As for default values, the way Groovy handles these is to create multiple methods. If you declare a method:
class Apple {
public void foo( bar="quux" ) { println bar }
}
Then this generates two methods in bytecode:
public void foo() { foo( 'quux' ) }
public void foo( bar ) { println bar }
If you run the above method inspector for this class containing the method foo, you'll see the output is:
foo : [arg0]
foo : []

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

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