Groovy对象是带有附加功能的Java对象。
POJO:普通的Java对象
POGO:用Groovy编写的对象,扩展了java.lang.Object,同时实现了groovy.lang.GroovyObject。
Groovy拦截器:扩展了GroovyInterceptable的Groovy对象。
public interface GroovyObject {
Object invokeMethod(String name, Object args);
Object getProperty(String propertyName);
void setProperty(String propertyName, Object newValue);
MetaClass getMetaClass();
void setMetaClass(MetaClass metaClass);
}
invokeMethod()、getProperty()和setProperty()使Java对象具有了高度的多态性,可以使用它们来处理运行中的方法和属性。getMetaClass()和setMetaClass()使创建代理拦截POGO的方法调用、在POGO上注入方法变得非常容易。
public interface GroovyInterceptable extends GroovyObject {
}
GroovyInterceptable接口扩展了GroovyObject接口,对于实现该接口的对象,其上所有的方法调用,都会被它的invokeMethod()方法拦截。
Groovy支持对POJO和POGO进行编程。对于POJO,Groovy维护了MetaClass的一个MetaClassRegistry;POGO有一个到其MetaClass的直接引用。
当我们调用一个方法时,Groovy会检查目标对象是一个POJO还是一个POGO。不同的对象类型,Groovy处理的方式不一样。
package exploring
class TestMethodInvocation extends GroovyTestCase{
void testInterceptedMethodCallOnPOJO(){
def val = new Integer(3)
Integer.metaClass.toString = {->'intercepted'}
assertEquals "intercepted",val.toString()
}
void testInterceptableCalled(){
def obj = new AnInterceptable()
assertEquals "intercepted",obj.existingMethod()
assertEquals "intercepted",obj.nonExistingMethod()
}
void testInterceptedExistingMethodCalled(){
AGroovyObject.metaClass.existingMethod2 = {-> 'intercepted'}
def obj = new AGroovyObject()
assertEquals "intercepted",obj.existingMethod2()
}
void testUnInterceptedExistingMethodCalled(){
def obj = new AGroovyObject()
assertEquals "existingMethod",obj.existingMethod()
}
void testPropertyThatIsClosureCalled(){
def obj = new AGroovyObject()
assertEquals 'closure called',obj.closureProp()
}
void testMethodMissingCalledOnlyForNonExistent(){
def obj = new ClassWithInvokeAndMissingMethod()
assertEquals "existingMethod",obj.existingMethod()
assertEquals "missing called",obj.nonExistingMethod()
}
def testInvokeMethodCalledForOnlyNonExistent(){
def obj = new ClassWithInvokeOnly()
assertEquals "existingMethod",obj.existingMethod()
assertEquals "invoke called",obj.nonExistingMethod()
}
def testMethodFailsONNonExistent(){
def obj = new TestMethodInvocation()
shouldFail (MissingMethodException){
obj.nonExistingMethod()
}
}
}
class AnInterceptable implements GroovyInterceptable{
def existingMethod(){}
def invokeMethod(String name,args){
'intercepted'
}
}
class AGroovyObject{
def existingMethod(){'existingMethod'}
def existingMethod2(){'existingMethod2'}
def closureProp = {'closure called'}
}
class ClassWithInvokeAndMissingMethod{
def existingMethod(){'existingMethod'}
def invokeMethod(String name,args){'invoke called'}
def methodMissing(String name,args){'missing called'}
}
class ClassWithInvokeOnly{
def existingMethod(){'existingMethod'}
def invokeMethod(String name,args){'invoke called'}
}
运行时,可以查询一个对象的方法和属性,以确定该对象是否支持某一特定行为。
- 可以使用MetaObjectProtocal的getMetaMethod()(MetaClass扩展了MetaObjectProtocal)来获得一个元方法。
- 如果要查找一个static方法,可以使用getStaticMetaMethod()。
- 要获得重载方法的列表,使用这些方法的复数形式——getMetaMethods()和getStaticMetaMethods()。
- getProperty()和getStaticProperty()可以获得元属性。
- 使用respondsTo()检查方法,使用hasProperty()检查属性。
MetaMethod的使用
str = "hello"
methodName = "toUpperCase"
methodOfInterest = str.metaClass.getMetaMethod(methodName)
println methodOfInterest.invoke(str)
print "Does String respond to toUpperCase()? "
println String.metaClass.respondsTo(str, 'toUpperCase') ? 'yes' : 'no'
print "Does String respond to compareTo(String)? "
println String.metaClass.respondsTo(str, "compareTo", 'test') ? 'yes' : 'no'
print "Does String respond to toUpperCase(int)? "
println String.metaClass.respondsTo(str, "toUpperCase", 5) ? 'yes' : 'no'
动态访问对象
def printInfo(obj){
usrRequestedProperty = 'bytes'
usrRequestedMethod = 'toUpperCase'
println obj[usrRequestedProperty]
println obj."$usrRequestedProperty"
println obj."$usrRequestedMethod"()
println obj.invokeMethod(usrRequestedMethod,null)
}
printInfo("hello")
要调用一个属性,可以使用索引操作符[],或使用点记号后跟一个计算属性名的GString。
迭代一个对象的所有属性:
println "Properties of 'hello are:"
'hello'.properties.each{ println it}