程式扎記: [ Groovy Doc ] ExpandoMetaClass - Overriding static methods and Adding properties (5)

標籤

2015年1月27日 星期二

[ Groovy Doc ] ExpandoMetaClass - Overriding static methods and Adding properties (5)

Overriding invokeMethod for static 
As an example of overriding invokeMethod for static methods, take this simple example: 
  1. class Stuff {  
  2.     static InvokeMe() {  
  3.         "foo"  
  4.     }  
  5.       
  6.     def invokeMe()  
  7.     {  
  8.         "stuff"  
  9.     }  
  10.       
  11.     def methodMissing(String name, args)  
  12.     {  
  13.         printf("Missing Method Name='%s' with input Argument(s):\n", name, args.getClass().getName())  
  14.         for(def arg:args) printf("\t%s (%s)\n", arg, arg.class.name)  
  15.         "miss"  
  16.     }  
  17. }  
  18.   
  19. Stuff.metaClass.'static'.invokeMethod = { String name, args ->  
  20.     def metaMethod = Stuff.metaClass.getStaticMetaMethod(name, args)  
  21.     printf("%sMethod Name='%s' with input Argument(s):\n", metaMethod==null?"Missing ":"", name, args.getClass().getName())  
  22.     for(def arg:args) printf("\t%s (%s)\n", arg, arg.class.name)  
  23.       
  24.     def result  
  25.     if(metaMethod) result = metaMethod.invoke(delegate,args)  
  26.     else {  
  27.         result = "static miss"  
  28.     }  
  29.     result  
  30. }  
  31.   
  32. assert "foo" == Stuff.InvokeMe()  
  33. assert "static miss" == Stuff.doStuff("Test"123)  
  34.   
  35. Stuff s = new Stuff()  
  36. assert "stuff" == s.invokeMe()  
  37. assert "miss" == s.invokeAny(123"test")  
Execution result: 
Method Name='InvokeMe' with input Argument(s):
Missing Method Name='doStuff' with input Argument(s):
Test (java.lang.String)
123 (java.lang.Integer)
Missing Method Name='invokeAny' with input Argument(s):
123 (java.lang.Integer)
test (java.lang.String)

So what is happening here? Well firstly we've overridden invokeMethod using the 'static' qualifier and by assigning it an appropriate closure, but in addition we first look-up a MetaMethod with the line: 
  1. def metaMethod = delegate.class.metaClass.getStaticMetaMethod(name)  
MetaMethod in Groovy is a method that is known to exist on the MetaClass whether added at runtime or whatever, thus we check if there is an existingMetaMethod and if there isn't we simply return "bar", hence the behaviour of the assert statements is correct. 

Adding properties 
Properties can be added in a couple of ways. Firstly you can use the instance method syntax seen previously: 
  1. class Book {  
  2.   String title  
  3. }  
  4. Book.metaClass.getAuthor << {-> "Stephen King" }  
  5.   
  6. def b = new Book(title:"The Stand")  
  7.   
  8. assert "Stephen King" == b.author  
In this case the property is dictated by the closure and is a read-only property. You can add the equivalent setter but then remember you will have to store the property somewhere for retrieval later so make sure you use thread safe code. For example you could store values in a synchronized Map using the object identity as the key: 
  1. def properties = Collections.synchronizedMap([:])  
  2.   
  3. Book.metaClass.setAuthor = { String value ->  
  4.    properties[System.identityHashCode(delegate) + "author"] = value  
  5. }  
  6. Book.metaClass.getAuthor = {->  
  7.    properties[System.identityHashCode(delegate) + "author"]  
  8. }  
This is not the only technique however. For example in a servlet container you may store the values in the currently executing request as request attributes (as is done in some cases in Grails). 

Alternatively you can simply assign a value as follows: 
  1. Book.metaClass.author = "Stephen King"  
  2. def b = new Book("The Stand")  
  3.   
  4. assert "Stephen King" == b.author  
In this case the property is mutable and has both a setter and getter. 

Supplement 
Using metMissing & propertyMissinhodg

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!