从Java检查CGLib代理的Groovy类

时间:2013-08-16 22:39:44

标签: java reflection groovy proxy-classes cglib

我正在尝试从Java中检查一些CGLib代理的Groovy类上的Groovy生成的方法,以了解方法的返回和参数类型。例如,考虑一下这个Groovy类:

class Person {
  String name
}

Groovy为name属性生成getName()setName()方法。 getName()可能会返回String,而setName()可能需要String

但是当通过CGLib代理此类并使用CGLib的MethodInterceptor拦截对getName的调用时,method.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

2 个答案:

答案 0 :(得分:1)

我认为你遇到的问题基本上就是你有Java思考调用方法会直接调用方法并完成它。好吧,甚至Java都没有,但这些东西都隐藏在JVM中。 Groovy并不擅长修改JVM,因此在调用final方法之前可能会调用一组方法。由于这是一个实现细节,序列可能会有所不同。由于Groovy是一种运行时元编程的语言,因此您可能根本不会调用目标方法。

无论如何,为了能够在Groovy中调用方法getName(),Groovy运行时首先必须获取调用Object的元类,这将导致调用getMetaClass()。如果你在这里拦截,那么你可能永远不会得到你想要的方法调用。

解决方案实际上很简单......你只需要过滤那些辅助方法。这将是以$开头的任何方法以及以此$开头的任何方法,以及super $和getMetaClass方法。过滤意味着您不会拦截,而只需使用Reflection继续调用。如果您遇到一个不在该集合中的方法,那么您很可能拥有目标。在你的例子中,method.getName()将返回“getName”。

答案 1 :(得分:0)

请检查/分享用于调用getName()方法的代码,因为有时在向Groovy对象请求属性时,它使用getPropertygetAttribute方法,并且他们调用getStaticMetaClass()方法,我认为这是实际发生在你身上的方法。

我的意思是,不是直接调用getName o Person对象,而是实际调用调用getProperty(..., personObject, 'name', ...)的方法getStaticMetaClass().getProperty(..., personObject, 'name', ...)

您也可以尝试调试代码,例如在您调用method.getName()的行上放置一个断点,然后查看堆栈跟踪如何调用getName()方法。