Groovy coercion to interface not known at compile-time - groovy

Some time ago I asked how to make a class implement an interface that it doesn't implement by declaration.
One possibility is as-coercion:
interface MyInterface {
def foo()
}
class MyClass {
def foo() { "foo" }
}
def bar() {
return new MyClass() as MyInterface
}
MyInterface mi = bar()
assert mi.foo() == "foo"
Now that I try to use it, I don't know what interface is needed at compile-time. I tried using generics like this:
interface MyInterface {
def foo()
}
class MyClass {
def foo() { "foo" }
}
class Bar {
public static <T> T bar(Class<T> type) {
return new MyClass() as T
}
}
MyInterface mi = Bar.bar(MyInterface.class)
assert mi.foo() == "foo"
But it raises the following exception:
Cannot cast object 'MyClass#5c4a3e60' with class 'MyClass' to class 'MyInterface'
How can I coerce to an interface that is only known at run-time?

interface MyInterface {
def foo()
}
interface AnotherInterface {
def foo()
}
class MyClass {
def foo() { "foo" }
}
class Bar {
static <T> T bar(Class<T> type) {
new MyClass().asType(type)
}
}
MyInterface mi = Bar.bar(MyInterface)
assert mi.foo() == "foo"
AnotherInterface ai = Bar.bar(AnotherInterface)
assert ai.foo() == "foo"

Related

Spock Metaprogramming getProperty()

I'd like to override the getProperty() method in a Spock test, per the documentation of get/setProperty. This is trivial in a normal Groovy class, but doesn't seem to work inside a Spock specification.
class MainSpec extends Specification {
#Override
def getProperty(String name) {
def value = metaClass.getProperty(this, name)
println "$name == $value"
return value
}
String foo = 'foo'
def test() {
expect:
foo
println foo
}
}
This example does not invoke the getProperty() method. It appears Spock is bypassing it somehow. Is there a way to hook into Spock's property resolution mechanism, or tell Spock to use my overridden method?
Yes, you can use "Expando" style, where the property should not be defined on the Spec class but is stored in a map (storage) and manipulated by setProperty and getProperty methods:
class MetaprogrammingSpec extends Specification {
def storage = [:]
#Override
def getProperty(String name) {
def value = storage[name]
println "$name == $value"
return value
}
#Override
void setProperty(String name, value) {
storage[name] = value
}
def test() {
when:
foo = 'bar'
then:
foo
println foo
}
}
Then the result is:
Update after comment: The getProperty() method is also called when you don't initialize the foo property. When you change the test in this way:
def test() {
expect:
foo
println foo
}
The result is as expected - getProperty() was called but test failes because foo is null:
It turns out that moving the property to a parent class is sufficient to make it pass through the getProperty() interceptor, even when the parent is another Specification class.
class BaseSpec extends Specification {
def foo = 'foo'
}
class MainSpec extends BaseSpec {
#Override
def getProperty(String name) {
def value = super.getProperty(name)
println "$name == $value"
return value
}
def test() {
expect:
foo
println foo
}
}

Call a method that inside a nested static class from the outer class by using a trait

I have a static class, 'Inner', and a nested static class, 'Deeper', in two different classes A,B. 'Inner' class implements the trait C that has a method called ping().
I want to execute the method hello() (that belongs to Deeper) from the ping() method in a way that each time I'll get either 'Hello A' or 'Hello B' according to the class that invoked the trait.
This is what I wrote (I'm using katalon-studio):
public class A
{
static class Inner implements C{
static class Deeper{
static void hello(){ println 'Hello A'}
}
}
}
public class B
{
static class Inner implements C{
static class Deeper{
static void hello(){ println 'Hello B'}
}
}
}
public static trait C {
static void ping() {
this.Deeper.hello()
}
}
A.Inner.ping()
B.Inner.ping()
I got the following error:
08-17-2018 04:46:57 PM - [ERROR] - Test Cases/V2/General/Draft FAILED
because (of) Variable 'Deeper' is not defined for test case.
Consider this code:
class A implements C {}
class B implements C {}
trait C {
def whoAmI() {
this.class.simpleName
}
}
// ---- main
assert "A" == new A().whoAmI()
assert "B" == new B().whoAmI()
Couldn't find an answer for this. However, using non-static classes, this could be implemented as follows:
public class A{
class Inner implements C{
A.Inner.Deeper d = new A.Inner.Deeper()
class Deeper {
void hello(){
println 'Hello A'
}
}
}
}
public class B{
class Inner implements C{
B.Inner.Deeper d = new B.Inner.Deeper()
class Deeper{
void hello(){
println 'Hello B'
}
}
}
}
public trait C{
public void ping(){
this.d.hello()
}
}
new A.Inner().ping()
new B.Inner().ping()

The Closure.delegate does not work with an object containing a methodMissing method?

My test code below:
#!/usr/bin/env groovy
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
}
}
def foo = {
bar()
}
foo.delegate = new Inner()
foo.call()
It gives result:
inner:bar
If I add another methodMissing method, like this:
#!/usr/bin/env groovy
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
}
}
// This method is added
def methodMissing(String name, args) {
println "outer:${name}"
}
def foo = {
bar()
}
foo.delegate = new Inner()
foo.call()
It gives result:
outer:bar
Why? I set the delegate to the closure 'foo'. Why isn't Inner. methodMissing called?
From this doc, I believe you'll want to change the resolution strategy. I have added a foo2 and some asserts to illustrate the contrast in behaviour:
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
return "inner:${name}"
}
}
def methodMissing(String name, args) {
println "outer:${name}"
return "outer:${name}"
}
def foo = { bar() }
foo.delegate = new Inner()
assert "outer:bar" == foo.call()
def foo2 = { bar() }
foo2.delegate = new Inner()
foo2.resolveStrategy = Closure.DELEGATE_FIRST
assert "inner:bar" == foo2.call()

What's an elegant way to have a reusable metaclass code in Groovy?

I would like to apply a meta-programming transformation to some of my classes, let's say by adding printXxx methods, like this:
class Person {
String name
}
def p = new Person()
p.printName() // does something
I have a rough idea how this can be done once I have a metaclass:
Person.metaClass.methodMissing = { name, args ->
delegate.metaClass."$name" = { println delegate."${getPropName(name)}" }
delegate."$name"(*args)
}
Now how do I turn this code into a reusable "library"? I would like to do something like:
#HasMagicPrinterMethod
class Person {
String name
}
or
class Person {
String name
static {
addMagicPrinters()
}
}
Define the behaviour you want to add as a trait
trait MagicPrinter {
void printProperties() {
this.properties.each { key, val ->
println "$key = $val"
}
}
}
Then add this trait to a class
class Person implements MagicPrinter {
String name
}
Now use it!
new Person(name: 'bob').printProperties()
You can go for a mixin approach:
class AutoPrint {
static def methodMissing(obj, String method, args) {
if (method.startsWith("print")) {
def property = (method - "print").with {
it[0].toLowerCase() + it[1..-1]
}
"${obj.getClass().simpleName} ${obj[property]}"
}
else {
throw new NoSuchMethodException()
}
}
}
You can mix it with a static block:
class Person {
static { Person.metaClass.mixin AutoPrint }
String name
}
def p = new Person(name: "john doe")
try {
p.captain()
assert false, "should've failed"
} catch (e) {
assert true
}
assert p.printName() == "Person john doe"
Or with expandoMetaClass:
class Car {
String model
}
Car.metaClass.mixin AutoPrint
assert new Car(model: "GT").printModel() == "Car GT"
Because 7 months later is the new 'now' :-)

groovy metaclass replace superclass method

Is there a way to replace using the metaclass object, a method that is of a super class.
Example:
class A {
def doIt(){
two()
println 'do it!'
}
protected two(){
println 'two'
}
}
class B extends A{
def doLast(){
doIt()
}
}
B b = new B();
b.doIt()
/*
* two
* doit!
*/
b.metaClass.two = {
println 'my new two!'
}
b.doIt();
/*
* my new two!
* do it!
*/
Since two and doIt are declared in the same class, groovy will skip the meta-object protocol for this call. You can override this behavior by marking the super class as GroovyInterceptable, which forces all method calls to go through invokeMethod. For example:
class A implements GroovyInterceptable {
def doIt(){
two()
println 'do it!'
}
protected two(){
println 'two'
}
}
class B extends A {
def doLast(){
doIt()
}
}
B b = new B()
b.doIt() // prints two
b.metaClass.two = {
println 'my new two!'
}
b.doIt() // prints my new two!

Resources