从Java中检查CGLib代理的Groovy类

3
我正在尝试从Java端检查一些CGLib代理的Groovy类生成的方法,以了解这些方法的返回类型和参数类型。例如,考虑以下Groovy类:
class Person {
  String name
}

Groovy为name属性生成getName()setName()方法。getName()可能会返回一个String,而setName()可能会接受一个String
但是,当通过CGLib代理此类并拦截针对getName的调用时,使用CGLib的MethodInterceptormethod.getName()返回getMetaClass,而method.getReturnType()返回groovy.lang.MetaClass
有没有办法从MethodInterceptor内部了解实际的方法名称和返回类型?
编辑:这是拦截Person.getName()调用时的调用堆栈:
ExplicitMappingInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 42    
GroovyMMTester$A$$EnhancerByCGLIB$$915b5b4.getMetaClass() line: not available   
CallSiteArray.createPogoSite(CallSite, Object, Object[]) line: 144  
CallSiteArray.createCallSite(CallSite, Object, Object[]) line: 161  
CallSiteArray.defaultCall(CallSite, Object, Object[]) line: 45  
AbstractCallSite.call(Object, Object[]) line: 108   
AbstractCallSite.call(Object) line: 112 
GroovyMMTester$Map.configure() line: 18 <-- Person.getName() call is in here, but doesn't show

为什么要使用CGLib而不是MetaClass?(来源:http://groovy.codehaus.org/Evaluating+the+MetaClass+runtime) - ChrLipp
我猜你现在调用的是 Person 对象上的 getName() 而不是直接调用 Person.getName(),对吗? - Alfergon
2个回答

1
我认为您的问题基本上是您使用Java思维直接调用方法并完成操作。 事实上,即使Java也不会这样做,但这些东西被隐藏在JVM中。Groovy没有修改JVM的豪华条件,因此在最终调用方法之前可能会调用一组方法。由于这是一个实现细节,因此顺序可能会有所变化。而且由于Groovy是一种具有运行时元编程的语言,您期望的目标方法可能根本不会被调用。
无论如何,在Groovy中能够调用getName()方法,Groovy运行时首先必须获取调用所在对象的元类,这会导致调用getMetaClass()。如果您在此处拦截,那么您可能永远无法达到所需的方法调用。
解决方案实际上很简单...您只需要过滤掉那些帮助方法。这将是任何以$开头和this $开头的方法,以及super $和getMetaClass方法。在这里过滤意味着您不会拦截,而是通过使用Reflection继续调用。如果遇到不在该集合中的方法,则您很可能拥有目标。在您的示例method.getName()中,将返回“getName”。

0
请检查/共享您用于调用getName()方法的代码,因为有时在向Groovy对象请求属性时,它会使用getPropertygetAttribute方法,而这两个方法都调用getStaticMetaClass()方法,我认为这实际上就是发生在您身上的事情。
我的意思是,与其直接调用Person对象的getName方法,实际上是调用getProperty(..., personObject, 'name', ...)方法,该方法调用getStaticMetaClass().getProperty(..., personObject, 'name', ...)方法。
您还可以尝试在调用method.getName()行上设置断点,然后查看堆栈跟踪,了解如何调用getName()方法。

OP想要使用Java反射知道返回类型。 :) - dmahapatro
我正在使用CGLib代理类,并使用CGLib的MethodInterceptor拦截对getName/setName的调用。这是我学习“属性类型”的起点。不幸的是,从拦截器中似乎没有办法甚至了解方法的名称,因为method.getName()返回$ getStaticMetaClass。 - Jonathan
不需要倒出一堆代码,我基本上只是使用CGLib的Enhancer类创建代理,并传入一个MethodInterceptor作为回调函数。因此,当MethodInterceptor的intercept方法被调用时,我试图确定被拦截的Groovy方法的名称和返回类型。我会尝试获取更多的调试输出... - Jonathan
然后,如果你正在做像cglib示例中那样的事情,然后直接调用getName(),我非常确定发生的是我在我的答案中提到的。 - Alfergon
已更新原帖并添加了调用堆栈。 - Jonathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接