get Groovy class' closure property names - groovy

Given the following Groovy class:
class MyClass {
def someClosure = {}
def someClosure2 = {}
private privateClosure = {
}
def someVal = 'sfsdf'
String someMethod() {}
}
I need a way to retrieve the names of all public properties that have closure assigned to them, so the correct result for this class would be ['someClosure', 'someClosure2'].
I can assume that all the classes of interest have a default constructor, so if it makes things easier, I could retrieve the properties from an instance via
def instance = MyClass.newInstance()

You can simply check the value of every groovy property:
class Test {
def aClosure = {}
def notClosure = "blat"
private privateClosure = {}
}
t = new Test()
closurePropNames = t.properties.findResults { name, value ->
value instanceof Closure ? name : null
}
assert closurePropNames == ['aClosure']
The private fields are not considered groovy properties, so they won't be included in the results.

Related

What is the static version of propertyMissing method in Groovy?

ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!

How do I store a list/array of classes in a Groovy variable?

I want to store a list/array of Java exception classes (e.g. NullPointerException, some custom exception classes, etc.) into a Groovy list/array, but I keep running into either casting problems or MissingPropertyException:
class Foo {
Exception[] foo
List bar
def setFoo(Exception[] values) {
this.foo = values
}
def setBar(List values) {
this.bar = values
}
}
f = Foo()
f.setFoo([NullPointerException.class])
f.setBar(Arrays.asList(NullPointerException.class))
But I can't seem to get it right. Any pointer is much appreciated. Thanks!
Changes to
class Foo {
Class[] foo
List bar
def setFoo(Class[] values) {
this.foo = values
}
def setBar(List values) {
this.bar = values
}
}
def f = new Foo()
f.setFoo([NullPointerException.class] as Class[])
f.setBar(Arrays.asList(NullPointerException.class))
foo should be an array of Class rather than Exception. (Exception is the instance of Exception Class)
You need to explicitly cast list to Class array, which does the conversion from list to array for you.
It can be done with just def list = [UserClass1, UserClass2]. In groovy, even .class not required.
You code should as below, isn't this simple?
class Foo {
def bar
}
def f = new Foo(bar: [NullPointerException, RuntimeException])
assert f.bar instanceof List<Class>
assert (f.bar as Class[]) instanceof Class[]
You can quickly try it online demo

How to pass a method as a Binding variable to Groovy's ConfigSlurper?

I was able to bind an object on Groovy's ConfigSlurper but not a method. Is that not possible?
Here's an example
String conf = """
k1 = "v1"
environments{
prod{
person.create("prod.id1"){
name = "prod.name1"
}
}
dev {
person.create("dev.id1"){
name = "dev.name1"
}
}
}
environments{
prod{
create("prod.id2"){
name = "prod.name2"
}
}
dev {
create("dev.id2"){
name = "dev.name2"
}
}
}
"""
def parser = new ConfigSlurper("prod")
Person person1 = new Person()
Person person2 = new Person()
parser.setBinding([person: person1, // <-- SUCCESS
create: person2.&create]) // <-- NOT SUCCESS?
println parser.parse(conf)
println "person1=${person1.dump()}"
println "person2=${person2.dump()}"
class Person{
String id
String name
public void create(String id, Closure c){
this.id = id
this.with(c)
}
}
Output is
[k1:v1, create:prod.id2, create.name:prod.name2]
person1=<Person#409b0772 id=prod.id1 name=prod.name1>
person2=<Person#205ee81 id=null name=null>
Please ignore any design flaws in the example.
person.create(...) is translated by Groovy to getProperty('person').invokeMethod('create', ...), it works since person is defined in the binding and create is defined on object returned by getProperty('person').
create.call(...) works because it's translated to getProperty('create').invokeMethod('call', ...). create property is defined via binding and it is of MethodClosure type which has call method defined.
However create(...) is translated to invokeMethod('create', ...). It fails because there is no method create and you cannot define methods via binding.

How do I get the annotation value 'used'

I want to retrieve the annotation value used from MyAnnot. I am getting 3 annotations in the list even though there are only 2. Also, I have tried obtaining the used field of MyAnnot but with no success. I would like to return a map where MyAnnot's used is the key and type as the map's value.
// Then, define your class with it's annotated Fields
class MyClass {
#MyAnnot(used = "Hey", type = "There")
String fielda
#MyAnnot(used = "denn", type = "Ton")
String fieldc
}
def findAllPropertiesForClassWithAnotation(obj, annotClass) {
def op = []
def annos = []
def i = 0
obj.properties.findAll { prop ->
obj.getClass().declaredFields.find {
it.name == prop.key && annotClass in it.declaredAnnotations*.annotationType()
annos=it.declaredAnnotations
i++
if(annos)
op << annos[0] as Set
// println"Props ${annos[0]}"
}
}
op.each{ println "${it} and i is ${i}"}
}
// Then, define an instance of our class
MyClass a = new MyClass(fielda: 'tim', fieldc: 'dennisStar')
// And print the results of calling our method
println findAllPropertiesForClassWithAnotation(a, MyAnnot)
First of all you need to mark you annotation with: #Retention(RetentionPolicy.RUNTIME) to make it available for processing at runtime, so it will be:
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnot {
String used()
String type()
}
Then, used and type are not fields, nor properties but methods, so they must be invoked and get.
The script will be:
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Retention
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnot {
String used()
String type()
}
class MyClass {
#MyAnnot(used="Hey" ,type="There")
String fielda
#MyAnnot(used="denn", type="Ton")
String fieldc
}
def findAllPropertiesForClassWithAnotation( obj, annotClass ) {
def c = obj.getClass()
c.declaredFields.findAll { field ->
field.isAnnotationPresent(annotClass)
}.collect { found ->
def a = found.getAnnotation(annotClass)
[(a.used()): a.type()]
}.sum()
}
MyClass a = new MyClass(fielda: 'tim', fieldc: 'dennisStar')
println findAllPropertiesForClassWithAnotation(a, MyAnnot)
Mind that passing only a class of annotation is not sufficient, since you don't know the methods (used and type) to be invoked on the annotation. The following method will work only for MyAnnot class.

In groovy, is there a way to check if an object has a given method?

Assuming that I have an object someObj of indeterminate type, I'd like to do something like:
def value = someObj.someMethod()
Where there's no guarantee that 'someObj' implements the someMethod() method, and if it doesn't, just return null.
Is there anything like that in Groovy, or do I need to wrap that in an if-statement with an instanceof check?
Use respondsTo
class Foo {
String prop
def bar() { "bar" }
def bar(String name) { "bar $name" }
}
def f = new Foo()
// Does f have a no-arg bar method
if (f.metaClass.respondsTo(f, "bar")) {
// do stuff
}
// Does f have a bar method that takes a String param
if (f.metaClass.respondsTo(f, "bar", String)) {
// do stuff
}
Just implement methodMissing in your class:
class Foo {
def methodMissing(String name, args) { return null; }
}
And then, every time you try to invoke a method that doesn't exist, you will get a null value.
def foo = new Foo();
assert foo.someMethod(), null
For more information, take a look here: http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing
You should be able to do something like:
SomeObj.metaClass.getMetaMethod("someMethod")
Or you can fall back to the good old Java reflection API.
You can achieve this by using getMetaMethod together with the safe navigation operator ?.:
def str = "foo"
def num = 42
def methodName = "length"
def args = [] as Object[]
assert 3 == str.metaClass.getMetaMethod(methodName, args)?.invoke(str, args);
assert null == num.metaClass.getMetaMethod(methodName, args)?.invoke(num, args);
if class :
MyClass.metaClass.methods*.name.any{it=='myMethod'}//true if exist
if object :
myObj.class.metaClass.methods*.name.any{it=='myMethod'}//true if exist
In very concise way you can use this:
if(someObj.&methodName){
//it means someObj has the method
}

Resources