在代理上调用接口默认方法

时间:2018-03-22 10:27:01

标签: java cglib dynamic-proxy

如何创建代理并调用默认接口方法,就好像它们是由代理超类实现的一样?例如:

interface Foo {

    default int returnSomething() {
        return 1;
    }

}

interface Bar extends Foo {

    default int returnSomethingMore() {
        return returnSomething();
    }

}

class Super implements Foo {

    @Override
    public int returnSomething() {
        return 2;
    }

}

我需要Bar的代理,在调用Super::returnSomething时将使用Bar::returnSomethingMore实现。

我试过了:

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Super.class);
enhancer.setInterfaces(new Class[] { Bar.class });
enhancer.setCallback((obj, method, args, proxy) -> {
    if (method.getName().equals("returnSomethingMore")) {

        return proxy.invokeSuper(obj, args);
        // -> NoSuchMethodError

        return proxy.invoke(obj, args);
        // -> StackOverflowError

        Class<?> declaringClass = method.getDeclaringClass();
        Lookup lookup = MethodHandles.lookup();
        return MethodHandles
                .privateLookupIn(declaringClass, lookup)
                .unreflectSpecial(method, declaringClass)
                .bindTo(obj)
                .invokeWithArguments(args);
        // -> returns 1, not 2
    }
});

如何创建returnSomethingMore方法返回2

的代理对象

1 个答案:

答案 0 :(得分:0)

我放弃了cglib(感谢SO&#39;标记我已经知道它不再处于积极开发状态)并采用了ByteBuddy我是我需要的代理:

@Test
public void defaultInterfaceMethodTest() {
    Class<? extends Super> loaded = new ByteBuddy()
            .subclass(Super.class)
            .implement(Bar.class).make()
            .load(this.getClass().getClassLoader()).getLoaded();
    Bar newInstance = (Bar) loaded.getConstructor().newInstance();
    int shouldBeTwo = newInstance.returnSomethingMore();
    Assert.assertEquals(2, shouldBeTwo);
}