Groovy: how to get properties declared in base class - reflection

In the following code, I need all the properties available in Child class (i.e. foo, bar). I am not interested in all other properties added by groovy.
class Parent {def foo}
class Child extends Parent {def bar}
So far none of these gets the result:
println Child.fields
println Child.properties.each{k,v->println "$k -> $v"}
println Child.declaredFields.findAll { !it.synthetic }.collect {it.name}
println Child.methods.findAll {it.name.startsWith("get")}.collect {it.name}
I am trying to find out some direct method which would give me this.

This will give you what you need:
assert ['foo', 'class', 'bar'] == B.metaClass.properties*.name

What about checking an instance? Also, i missed the extends in Child
class A { def foo }
class B extends A { def bar }
b = new B(foo: 'foo', bar: 'bar')
assert b.properties == [foo: 'foo', class: B, bar: 'bar']

Related

Syntax of the method of an instantiated object: can't seem to get it right

I want to get a pointer to an object method, for instance for this class
class Foo {
has $thing = "baz";
method bar() { say $thing }
};
sub quux( Callable $flimflam ) {
$flimflam()
};
my $foo = Foo.new;
I want to grab of the $foo.bar method pointer to pas it to quux. However, this
quux(&($foo.bar))
fails with Type check failed in binding to parameter '$flimflam'; expected Callable but got Bool (Bool::True)␤ in sub quux
This does not work either
quux($foo.bar)
maybe because it takes no parameters; however, if we change the definition of bar to:
method bar($some ) { say $some ~ $thing }
Then the error for the call above becomes Too few positionals passed; expected 2 arguments but got 1␤ in method bar, the error creeps up to bar itself, which means the object itself does not get in.
I have checked out this answer, but it's for a class method (new) and it involves using the meta-object protocol. Would there be a simpler way of doing that?
You can get the "static" method with .^lookup (the ^ indicates that it's a call on the meta object).
That method is not bound to the invocant $foo in any way, so you have to call it as
class Foo {
has $thing = "baz";
method bar() { say $thing }
};
sub quux( Callable $flimflam ) {
$flimflam()
};
my $foo = Foo.new;
my $method_bar = $foo.^lookup('bar');
$method_bar($foo);
You can use a closure to bind the method to the invocant:
my $bound_method = -> |c { $method_bar($foo, |c) }
Perl 6 also has a shortcut built in for that:
my $bound_method = $method_bar.assuming($foo);
But you can see that you could abbreviate the whole thing as
my $callback = { $foo.bar() }
or if the method potentially takes more arguments
my $callback = -> |c { $foo.bar(|c) }

flowtype: $Subtype and typeof fail when used in generic types

It appears that class types in flow always refer to instances of that class and one uses typeof to refer to the actual class itself. So, if I want a variable to refer to a subclass (not an instance) of a base class, I can do:
class MyBaseClass {}
class MySubClass extends MyBaseClass {}
let a: $Subtype<MyBaseClass> = MySubClass; // fails
let b: $Subtype<MyBaseClass> = new MySubClass(); // works, but I don't want this.
let c: $Subtype<typeof MyBaseClass> = MySubClass; // works! Ok, we're good
However, I can't seem to do this with type parameters! For example, the following:
type GenericSubclass<T> = $Subtype<typeof T>;
// fails with `^ identifier `T`. Could not resolve name`
If I try the following Typescript trick (see Generic and typeof T in the parameters), it also fails:
type ValidSubclass<T> = { new(): T };
const c: ValidSubclass<BaseClass> = MySubClass;
// fails with: property `new`. Property not found in statics of MySubClass
Note that I tried new, __proto__ and constructor.
What gives? Is there a workaround?
typeof MyBaseClass
is
Class<MyBaseClass>
so you can do
type GenericSubclass<T> = $Subtype<Class<T>>;

Kotlin: How can a child class use a parent's extension function in the super constructor call?

How can a child class use its parent's extension function in a lambda field?
Consider this parent class:
abstract class Parent(val field: Int.() -> Any) {
fun Int.print() = println(this)
}
And this child:
class Child : Parent({
print() // DOESN'T COMPILE
this.print() // DOESN'T COMPILE
5.print() // DOESN'T COMPILE
val value = 5
value.print() // DOESN'T COMPILE
})
The reason why you cannot use Parent's extension inside Child super constructor call argument is that its Parent part is not initialized yet at that point and thus cannot be used as dispatch receiver of the extension.
Member extension functions can use the eclosing class' members and this means that they need an instance of the class to be called with, and you cannot use the instance in its own constructor arguments.
Otherwise, you can use Parent's extensions anywhere inside the Child members and in constructors (or init blocks), because super constructor is called before own constructors:
class Child : Parent {
constructor(): super({}) {
5.print()
}
fun f() {
5.print()
}
val g: (Int) -> Unit = { it.print() }
}
In your example the lambda in question is not a field of Parent (strictly speaking), but a parameter to a function (class constructor).
The lambda is constructed (resolved) before any object, Child or Parent, is created. That's why methods can be resolved and the lambda is not in the scope of Child.
PS
The name of the topic suggests the following situation, but it compiles all right:
class Child : Parent({}) {
val lambdaField: Int.() -> Any = {
print()
this.print()
5.print()
}
}

Is it possible to implement collection literal initializers for custom classes in Groovy?

For example LibGDX framework has custom made collection classes such as Array<T> and ObjectMap<K, V> which aid app/game performance. Would it be possible to create a literal initializer so that Array could be initialized with for example [1,2,3,4] and ObjectMap with [key:"value"].
I know that access operators [] can be added to objects by implementing putAt/getAt methods but haven't seen anything about literal initializers.
Are they locked down into the language itself like operator overriding is in Java or is there a way to create list/map initializers for custom classes?
One possible method is to manipulate the existing LinkedHashMap.asType() method to accept ObjectMap as a parameter:
def originalMethod = LinkedHashMap.getMetaClass().getMetaMethod("asType", Class)
LinkedHashMap.getMetaClass().asType = { Class clazz ->
if(clazz == ObjectMap) {
def map = new ObjectMap()
delegate.each { key, value -> map.put(key, value) }
map
}
else {
originalMethod.invoke(delegate, clazz)
}
}
You can then do:
def map = [a:1] as ObjectMap
Another option would be to add a method toObjectMap() to the base Map metaClass like so:
Map.getMetaClass().toObjectMap = { ->
def map = new ObjectMap()
delegate.each { key, value -> map.put(key, value) }
map
}
Then, you can do:
def map2 = [a:2].toObjectMap()
Or, just write a utility method to convert Maps to ObjectMaps ;-)

Groovy - Ignore extra attributes in a map during object instantiation

Is there a way to make groovy ignore extra attributes in a map during object instantiation? Example:
class Banana{
String name
}
def params = [name:'someGuy', age:13]
new Banana(params)
In this example, groovy throws a No such property: age exception (obviously because age isn't defined in the Banana class. Without resorting to manually mapping only the desired attributes from the map to the constructor of the Banana class, is there a way to tell Banana to ignore the extra attributes?
I noticed that Grails domain classes do not suffer from this problem, and I would like the same behavior here!
Thanks for your help and advice!
There is a simpler way to deal with this case.
In your bean, just implement a trait
trait IgnoreUnknownProperties {
def propertyMissing(String name, value){
// do nothing
}
}
class Person implements IgnoreUnknownProperties {
String name
}
map = ["name": "haha", "extra": "test"]
Person p = new Person(map)
println p.name
Unfortunately, there's no built in way to do this in groovy. Grails does it by generating its own constructors for domain objects. A simple workaround is to use a constructor like this:
Banana(Map map) {
metaClass.setProperties(this, map.findAll { key, value -> this.hasProperty(key) })
}
Another way that does not impact performance if all properties are present:
public static Banana valueOf(Map<String, Object> params) {
try {
return new Banana(source)
} catch (MissingPropertyException e) {
log.info(e.getMessage())
source.remove(e.property)
return valueOf(source)
}
}
Similar to #JiankuanXing's answer (which is a perfect answer :) ), but instead of using trait your class can extends Expando and add the propertyMissing method:
class Banana extends Expando {
String name
def propertyMissing(name, value) {
// nothing
}
}
def params = [name:'someGuy', age:13]
new Banana(params)
The use of trait fits probably better this case since it allow behavior composition and you can add the trait to all the class object which need it. I only add this alternative since Expando can be used since groovy 1.5 version while traits are introduced in groovy 2.3.
Hope it helps,

Resources