使用Javassist修改超类中声明的方法

时间:2015-04-06 09:41:54

标签: java bytecode javassist

我正在尝试修改在超类中声明的CtMethod#insertBefore方法。但是,Javassist似乎无法实现。

private class AbstractTestDataSource {
    public Connection getConnection() throws SQLException {
        return connection;
    }
}

private class TestDataSource extends AbstractTestDataSource implements DataSource { 
    public Connection getConnection(String username, String password) throws SQLException {
        return connection;
    }
    // other methods omitted
}

这是我的ClassFileTransformer

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                  ProtectionDomain protectionDomain, byte[] classfileBuffer)
        throws Exception {
    if (!className.equals("org/example/TestDataSource")) {
        return classfileBuffer;
    }
    final CtClass ctClass = createCtClass(loader, classfileBuffer);
    for (CtMethod method : ctClass.getMethods()) {
        if (method.getName().equals("getConnection")) {
            System.out.print(method.getName());
            System.out.println(method.getSignature());
            method.insertBefore("System.out.println(\"foo\");");
        }
    }
    return ctClass.toBytecode();
}

当我调用getConnection(String, String)方法时,foo会打印到控制台,但如果我调用getConnection()中声明的AbstractTestDataSource方法,则不会发生任何事情。 我做错了什么?

修改

我可以确认这两种方法都是检测的,因为这是打印到控制台的内容:

getConnection(Ljava/lang/String;Ljava/lang/String;)Ljava/sql/Connection;
getConnection()Ljava/sql/Connection;

2 个答案:

答案 0 :(得分:1)

我的解决方案是检查getConnection方法是否在当前类之外的类中声明。

if (!ctClass.equals(method.getDeclaringClass())) {
    method = overrideMethod(ctClass, method);
}

如果是这样,我创建(并因此覆盖)getConnection方法并委托给超类。

private CtMethod overrideMethod(CtClass ctClass, CtMethod getConnectionMethodOfSuperclass)
        throws NotFoundException, CannotCompileException {
    final CtMethod m = CtNewMethod.delegator(getConnectionMethodOfSuperclass, ctClass);
    ctClass.addMethod(m);
    return m;
}

它不是理想的解决方案,但它工作正常。

答案 1 :(得分:0)

您没有覆盖超类中的方法getConnection(),该方法具有此方法签名:

public Connection getConnection() throws SQLException

在您的子类中,您必须使用相同的方法签名覆盖此方法,否则您只是在子类中创建一个新方法