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.
Related
I have a script where one of the closure delegates with another class object.
Now this closure should take no parameters or multiple parameters and inside code it should access passed delegated object methods
suppose
class Foo {
public boolean verifyName(String name);
public boolean verifyNameAndType(String name, PersonType type);
public boolean verifyNameAndTypeAndAge(String name, PersonType type, int age);
}
class Bar {
def getNames = { String name ->
if (verifyName(name)){
// do something
}
};
def getNames = { String name, PersonType personType ->
if (verifyNameAndType(name, personType)) {
// do something
}
}
def getNames = { String name, PersonType personType, int age ->
if (verifyNameAndTypeAndAge(name, personType, age)) {
// do something
}
}
Foo foo = new Foo()
Bar bar = new Bar();
bar.delegate = foo;
Closure NAME = bar.getNames;
NAME closure is available to user where he types
NAME('shakira');
NAME('affan', DOCTOR);
NAME('siddique', TEACHER, '45455555');
base on parameter it should call specific closure but it seems multiple closure with same name is not allowed.
also user can provide null values inside parameters but still it will call specific closure even if it is null
e.g NAME('shakira', null) should call exact closure getNames(name, personType)
I have already checked this url but my logic will not cover my logical part where User provides null parameters inside method
Groovy Closure with parameters
you can't define several variables with the same name in one class,
however you can define several methods with one name but with different parameters
so your code could look like this:
class Foo {
public boolean verifyName(String name){println 'verifyName'}
public boolean verifyNameAndType(String name, String type){println 'verifyNameAndType'}
public boolean verifyNameAndTypeAndAge(String name, String type, int age){println 'verifyNameAndTypeAndAge'}
}
class Bar {
#Delegate Foo delegate
def getNames ( String name ){
println '1'
verifyName(name)
}
def getNames (String name, String personType ){
println 2
verifyNameAndType(name,personType)
}
def getNames (String name, String personType, int age ){
println 3
verifyNameAndTypeAndAge(name,personType,age)
}
}
Foo foo = new Foo()
Bar bar = new Bar(delegate:foo);
Closure NAME = bar.&getNames; // &methodName returns a method closure
//NAME closure is available to user where he types
NAME('shakira');
NAME('affan', 'DOCTOR');
NAME('siddique', 'TEACHER', 45455555);
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!
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.
I'm new to groovy, and I'm reading the source of a project gretty
import org.codehaus.jackson.map.ObjectMapper
class JacksonCategory {
static final ObjectMapper mapper = []
...
}
I don't understand the code ObjectMapper mapper = [], what does [] mean here? I thought it's a list, but how to assign it to a ObjectMapper?
UPDATE
Depends on Dunes's answer, seems [] means invocation of default constructor. So, it means:
static final ObjectMapper mapper = new ObjectMapper()
But:
String s = []
println s // -> it's `[]` not ``
And
Integer i = []
throws exception:
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[]'
with class 'java.util.ArrayList' to class 'java.lang.Integer'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[]' with class
'java.util.ArrayList' to class 'java.lang.Integer'
It's a call to the default constructor of ObjectMapper.
http://mrhaki.blogspot.com/2009/09/groovy-goodness-using-lists-and-maps-as.html
It seems [] is always created as an empty ArrayList, but when assigned to a separate type groovy tries to do type coercion and find an appropriate constructor.
With strings it just calls the toString method on the list and makes that the string. For objects it looks for constructors with the appropriate number and type of arguments.
Groovy does not expect to have to do this for java library classes that extend Number (Integer, BigDecimal, etc) and throws a ClassCastException instead.
Examples:
class A {
String value;
A() { this("value"); }
A(String value) { this.value = value; }
}
def A defaultCons = [];
// equivalent to new A()
def A argsCons = ["x"];
// equivalent to new A("x")
def list = [1,2];
// literal ArrayList notation
def String str = [];
// equivalent to str = "[]"
println "A with default constructor: " + defaultCons.value;
println "A with String arg constructo: " + argsCons.value;
println "list: " + list;
println "str: " + str;
is there a convenient way to iterate Object's properties and to check annotations for each?
You can do it this way:
// First, declare your annotation
import java.lang.annotation.*
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface MyAnnot {
}
// Then, define your class with it's annotated Fields
class MyClass {
#MyAnnot String fielda
String fieldb
#MyAnnot String fieldc
}
// Then, we will write a method to take an object and an annotation class
// And we will return all properties of the object that define that annotation
def findAllPropertiesForClassWithAnotation( obj, annotClass ) {
obj.properties.findAll { prop ->
obj.getClass().declaredFields.find {
it.name == prop.key && annotClass in it.declaredAnnotations*.annotationType()
}
}
}
// Then, define an instance of our class
MyClass a = new MyClass( fielda:'tim', fieldb:'yates', fieldc:'stackoverflow' )
// And print the results of calling our method
println findAllPropertiesForClassWithAnotation( a, MyAnnot )
In this instance,this prints out:
[fielda:tim, fieldc:stackoverflow]
Hope it helps!