通过 reflection/javassist 调用不存在的函数

Calling a function that does not exist via reflection/javassist

我需要调用一个函数 - (属性 的 getter 和 setter),但我的问题是,属性 的名称是在运行时生成的(某些变量的名称 + 数字).

是否可以通过 javassist 或 gclib 操纵字节码,以便将函数调用定向到某个代理 object/function,并从被调用的函数名中提取真实的方法名称和编号,以便我可以在之后调用函数(以数字作为参数)?

我尝试了以下方法,但没有用:

MethodHandler handler = new MethodHandler() {
        @Override
        public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) {
             String realMethodName=thisMethod.substring(0,5);
             Integer param=Integer.parseInt(thisMethod.substring(5));
            Method m = self.getClass().getMethod(realMethodName);
            m.invoke(self,param);
            return null;
        }
    };

我认为这可能是使用 Java 反射代理对象可能派上用场的少数场景之一。

您可以定义一些接口,但将方法委托给(动态)调用处理程序,后者将调用那些 "getter/setter" 方法。

旁注:在实现这样的调用处理程序时,您必须了解对相应对象的任何方法调用都会触发其 "invoke" 方法;当您调用 toString 或 equals 或从 Object 继承的任何其他内容时发生的事件。

编辑:还有一个(不同的)想法:你确定你需要创建动态方法名吗?如果您有一些数字(或基于字符串)键 - 例如不使用 Map 怎么办?

喜欢

    Map<WhateverKeyType,YourPropertyClass> 

那会是 "normal java" 处理问题的更多方式(而不是考虑反射或字节码操作)。

如果您想实现类似的东西但可以考虑使用除 javassist 之外的其他库,请考虑 using Byte Buddy(我写的,以供披露)。

考虑到,你有一个接口

interface Foo { Object getProperty() }

您想实施以访问 bean属性 的

class Bar { Object getAbc123() { ... } }

然后使用 Byte Buddy,您可以实现 class

Foo accessor = new ByteBuddy()
  .subclass(Foo.class)
  .method(named("getProperty"))
  .intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("getAbc123"))
                        .on(new Bar()))
  .make()
  .load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
  .getLoaded()
  .newInstance();

getProperty 的调用重定向到您选择的方法的接口。通过一些自定义,您一定可以创建更通用的解决方案。