当前位置: 首页 > 知识库问答 >
问题:

bytebuddy能否拦截方法调用并使其调用第二个对象的私有方法?

凌波峻
2023-03-14

给定一个类a,使用一个公共方法覆盖(B that,C arg),第二个类B,使用一个私有方法调用(C arg)。有没有可能用bytebuddy生成一个子类,该子类将调用私有方法callMe(C arg),从实现的overrideMe(B that,C arg)?这基本上会模拟JVM反射生成的MethodAccessor,它正是这样做的。

目前,我正在尝试使用以下方法调用:

Method callMeHandler = B.class.getDeclaredMethod("callMe");
callMeHandler.setAccessible(true);
MethodCall methodCall = MethodCall.invoke(callMeHandler).onArgument(0);
if(callMeHandler.getParameterCount() == 1)
    methodCall = methodCall.withArgument(1);

Composable coercedMethodCall = methodCall
           .withAssigner(ReferenceTypeAwareAssigner.INSTANCE, Typing.DYNAMIC);

String className = callMeHandler.getDeclaringClass().getName()
       + "$_generatedAccessor$" + callMeHandler.getName()
       + "$" + accessorCounter.getAndIncrement();

new ByteBuddy().subclass(GeneratableHandlerInvocation.class)
               .name(className)
               .method(ElementMatchers.named("invoke"))
               .intercept(Advice.to(GeneratableHandlerInvocation.class)
                                .wrap(coercedMethodCall))
               .make()
               .load(callMeHandler.getDeclaringClass().getClassLoader())
               .getLoaded()
               .newInstance();

,但它抱怨

java.lang.IllegalStateException: Cannot invoke private void com.mycompany.secret.B.callMe() virtually
    at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForVirtualInvocation$WithImplicitType.invoke(MethodCall.java:2124)
    at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2400)
    at net.bytebuddy.asm.Advice$Appender$EmulatingMethodVisitor.resolve(Advice.java:7156)
    at net.bytebuddy.asm.Advice$Appender.apply(Advice.java:7109)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:614)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:603)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:521)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4102)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1612)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2560)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2662)
    at com.mycompany.secret.Main.defineTheSpecialClass(Main.java:190)

共有1个答案

傅元章
2023-03-14

不,这是不可能的。JVM的字节码验证器禁止它。因此,Byte Buddy首先不允许您创建这样的方法调用。

如果您想更改一个类并允许这样的调用,请查看Byte Buddy的代理API和允许您更改现有代码Advice类。

 类似资料:
  • 我想截取在一个类的所有实例上调用的每个setter方法,然后在另一个类对象上调用一个方法,参数对应于第一个类的每个实例的一些字段值。为此,我想使用ByteBuddy API,但我也想为指定类的所有实例只创建一个子类 例如,我编写了以下代码: 我将为每个资源类型创建的每个子类保存在映射中,以便为每个资源类型只创建一个子类。这里的问题是,对于创建的子类的所有实例,传递给在目标对象上调用的方法“upda

  • 问题内容: 我有这个代码 有什么方法可以在没有子类化或修改类且没有工厂的情况下拦截呼叫? 编辑:抱歉忘了提到这是在Android平台上。 问题答案: 您是否考虑过面向方面的编程,甚至还考虑过AspectJ?有关AspectJ / Android的信息,请参见此处和此处。

  • 我正在尝试使用来做同样的事情,现在我使用哪个注释来捕获相关的对象,切入点表达式应该是什么?我尝试了,但这是一个void方法,如何捕获该方法的参数?我是AOP的初学者,所以如果这个问题太琐碎,请原谅。 解决方案:使用spring AOP获取方法参数?

  • 问题内容: 我正在用python实现RESTful Web服务,并想通过拦截函数调用并记录其执行时间等方式来添加一些QOS记录功能。 基本上,我想到了所有其他服务都可以从中继承的类,该类会自动覆盖默认方法的实现,并将其包装在logger函数中。实现此目标的最佳方法是什么? 问题答案: 像这样吗 这暗示着在您的方法中添加装饰器(如果您愿意,也可以基于此创建一个显式装饰器): 当您现在尝试类似的方法:

  • 问题内容: 我正在使用Java EE 6和Jboss AS7.1,并尝试使用拦截器绑定(来自jboss网站的示例)。 我有一个InterceptorBinding注解: 拦截器: 还有一个豆: 但是拦截器没有被称为。。。 在编写此代码时将调用拦截器: 谢谢你的帮助。 问题答案: 您是否按照参考示例中的说明启用了拦截器? 缺省情况下,bean档案没有通过拦截器绑定绑定的已启用拦截器。必须通过将侦听器

  • 问题内容: 我正在使用Mockito测试旧版JAAS / LDAP登录模块。 该接口定义了以下功能: 我期望包含一个,这是需要进行操作才能通过测试的对象。 有没有一种方法可以有效地对此进行模拟,或者我可以通过实施存根实现更好呢? 问题答案: 对于返回的函数,请使用doAnswer() 和执行拦截必须在作为参数,例如,作为一个匿名类: 在这种情况下将是数组!