What is the static version of propertyMissing method in Groovy? - 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!

Related

Does Groovy "as" operator create a subclass at run time for User defined classes?

In Groovy When I write the below code in a groovy script.
class Emp {
public String getId() {
return "12345";
}
}
def coercedInstance = [
getId: {
"99999"
}
] as Emp
println new Emp().getId()
println coercedInstance .getId()
Using the as Operator here, am I creating a sub class of the actual Emp class at runtime and providing the method body at run time?
I have seen other stack overflow articles and i have learnt that Groovy uses DefaultGroovyMethods.java & DefaultTypeTransformation.java to do the coercion. But could not figure out if it was subclassing or not.
Yes, an as operator creates an object which type is a subclass of the target class. Using DefaultGroovyMethods.asType(Map map, Class clazz) generates (in a memory) a proxy class that extends given base class.
class Emp {
public String getId() {
return "12345";
}
}
def coercedInstance = [
getId: {
"99999"
}
] as Emp
assert (coercedInstance instanceof Emp)
assert (coercedInstance.class != Emp)
assert (Emp.isAssignableFrom(coercedInstance.class))
println coercedInstance.dump() // <Emp1_groovyProxy#229c6181 $closures$delegate$map=[getId:coercion$_run_closure1#7bd4937b]>
What happens in your case specifically is the following:
The asType method goes to line 11816 to execute ProxyGenerator.INSTANCE.instantiateAggregateFromBaseClass(map, clazz);
In the next step, ProxyGeneratorAdapter object gets created.
In the last step, adapter.proxy(map,constructorArgs) gets called to return a newly generated class that is a proxy of the base class.

Groovy call field

I'm trying to put into the field an object that supports a call operation, and then to call him. I can do it without intermediate reading fields in a variable?
My attempt looks like this:
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field()
}
}
​
But I receive groovy.lang.MissingMethodException.
What can you do? Or can anyone give a proof where it's written that we can't call the field?
Membership (.) has lower order of precedence than function/method/call invocation (()). Thus this line:
return x.field()
is interpreted as "invoke the 'field' method on the 'x' object".
To get Groovy to parse the code as you desire, the minimal change would be to regroup using parentheses, as follows:
return (x.field)()
which is (ultimately) interpreted as "invoke the 'call' method on the 'field' object member of the 'x' object", as desired.
It is trivial issue. Not required to have parenthesis for field.
Change from:
return x.field()
To:
return x.field
If you want to execute call method further, then use below code snippet.
Note that static method return type is changed.
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field
}
}
​GroovyRunnerDynamic.make(1)​.call()​
Output would be : 5
Not sure why argument to make method is done here, seems to be not used in the above code.
Alternatively, you can change
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field.call()
}
}
​GroovyRunnerDynamic.make(1)
EDIT: Based on OP's implicit call.
Not really sure how it is working, but the below does implicit call. Just assign x.field to a variable and just add parenthesis for that as shown below.
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
def fun = x.field
fun()
}
}
GroovyRunnerDynamic.make(1)

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.

How to use closure to capture the invocation by specific type and ignore others?

I have a mock with a method that can accept all children of an abstract type.In a test,this method may be invoked by different children multiple times,and I want to check that it is invoked by specific type once like this:
1*mockObject.method(_) {SpecificType ct->
//check the ct's field value
}
the problem is that the closure always capture the first invocation due to:
mockObjectt.method(_)
can't distinguish different children types,so it match all invocations,then I tried another way like this:
1*mockObject.method({it instanceof SpecificType}) {SpecificType ct->
//check the ct's field value
}
but the problem of this way is that:
{SpecificType ct->
//Here,any check will return true,
//I think the checkings in here are ignored
}
is ignored always(I think I misused the groovy's closure here)
So question is:
Is there elegant way to capture the invocation by specific child type with specific values and ignore others?
What about: 1*mockObject.method({it instanceof SpecificType && it.field == fieldValue }) ?
Take a look at this sample code:
import spock.lang.Specification
class SimpleTestSpec extends Specification {
private static class A { }
private static class B extends A { }
private static class C extends B { }
private static class D extends A { }
private static class TestClass {
String foo(A value) {
return "A: ${value}"
}
String foo(B value) {
return "B: ${value}"
}
String foo(C value) {
return "C: ${value}"
}
String foo(D value) {
return "D: ${value}"
}
}
private static class ComponentClass {
private final TestClass testClass
ComponentClass(TestClass testClass) {
this.testClass = testClass
}
String foo(A value) {
return testClass.foo(value)
}
}
TestClass testClassMock = Mock(TestClass)
ComponentClass componentClass = new ComponentClass(testClassMock)
def setup() {
testClassMock.foo(_ as D) >> "DDD"
testClassMock.foo(_ as C) >> "CCC"
testClassMock.foo(_ as B) >> "BBB"
testClassMock.foo(_ as A) >> "AAA"
}
def "should use mocked DDD result"() {
when:
String result = testClassMock.foo(new D())
then:
result == "DDD"
}
def "should use mocked CCC result"() {
when:
String result = testClassMock.foo(new C())
then:
result == "CCC"
}
def "should use mocked BBB result"() {
when:
String result = testClassMock.foo(new B())
then:
result == "BBB"
}
def "should use mocked AAA result"() {
when:
String result = testClassMock.foo(new A())
then:
result == "AAA"
}
def "should record invocation based on dynamic type"() {
when:
componentClass.foo(new C())
then:
1 * testClassMock.foo(_ as C)
}
def "should return result associated with mocked invocation in runtime"() {
when:
String result = componentClass.foo(new D())
then:
result == "DDD"
}
}
Gist file: https://gist.github.com/wololock/c59151b67d4c9b0c0c8e
You can specify expected type of an argument using as casting operator. But there is one tricky part - you need to stub class behavior in particular order: from most specific to most general. Try to mix the order in setup() and then you will see that tests will start failing.
You can also make use of Groovy's dynamic method invocation - notice how ComponentClass behaves with injectest TestClass instance which was previously stubbed with expected behavior. You can also count the number of invocations associated with specific type even if external call was made through the most general type method.
I hope it will help you resolve your problem. Best!

groovy generic fluent builder

I'd like to create a simple wrapper, which would allow calling objects methods as a fluent interface. I've been thinking about rewriting methods of a class upon creation, but this doesn't seem to work. Is this possible in some way with groovy metaprograming?
I have this kind of code snippet so far:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
delegate.class.getMethods().each { method ->
def name = method.getName()
FluentWrapper.metaClass."$name" = { Object[] varArgs ->
method.invoke(wrapped, name, varArgs)
return this
}
}
}
def methodMissing(String name, args) {
def method = delegate.getClass().getDeclaredMethods().find { it.match(name) }
if(method) {
method.invoke(delegate,name, args)
return FluentWrapper(delegate)
}
else throw new MissingMethodException(name, delegate, args)
}
}
Assuming example Java class:
class Person {
void setAge()
void setName()
}
I'd like to be able to execute the following piece of code:
def wrappedPerson = new FluentWrapper(new Person())
wrappedPerson.setAge().setName()
I'm using Groovy 1.6.7 for this.
This is all Groovy, and I'm using 1.8.6 (the current latest), but given this Person Class:
class Person {
int age
String name
public void setAge( int age ) { this.age = age }
public void setName( String name ) { this.name = name }
public String toString() { "$name $age" }
}
And this FluentWrapper class:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
method.invoke( delegate, args )
return this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Then, you should be able to do:
def wrappedPerson = new FluentWrapper(new Person())
Person person = wrappedPerson.setAge( 85 ).setName( 'tim' ).delegate
And person should have the age and name specified
I find #tim_yates' answer nice, but you couldn't access delegate methods' return values (something one usually likes doing, even for Builders in the case of build() :)
Moreover, if this wasn't intended for a Builder but for an object with a chainable interface (like that of jQuery wrapped objects in JS), it would be a serious issue.
So I'd put the wrapper like this:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
def result = method.invoke(delegate, args)
return result != null ? result : this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Note the elvis operator is unsuitable since a falsy value would never get returned.
Of course, it's up to the invoker to know wether a method is chainable or not, but that could be overcome with method annotations if neccesary.

Resources