为接口默认方法的Java InvocationHandler实现添加支持

Adding Support to Java InvocationHandler Implementations for Interface Default Methods

Java 8 introduced default methods to interfaces. Existing InvocationHandler implementations will not invoke default interface methods. This short article documents the necessary changes. Note: It first describes the implementation based on a reading of the documents and then provides a working implementation for Java 8.

鉴于调用处理程序实施:

    @Override
    public Object invoke(Object proxy,
                         Method method, Object[] argv) throws Throwable {
        Object result = null;
        /*
         * Logic to calculate result.
         */
        return result;
    }

Java 8解决方案似乎是通过以下方式扩展实现以调用任何接口默认方法:方法句柄:

    @Override
    public Object invoke(Object proxy,
                         Method method, Object[] argv) throws Throwable {
        Object result = null;
        Class<?> declaringClass = method.getDeclaringClass();

        if (method.isDefault()) {
            result =
                MethodHandles.lookup()
                .in(declaringClass)
                .unreflectSpecial(method, declaringClass)
                .bindTo(proxy)
                .invokeWithArguments(argv);
        } else {
            /*
             * Logic to calculate result.
             */
        }

        return result;
    }

If the Method is "default" then the target interface method is invoked. Otherwise, the 一世nvocationHandler implementation processes as before. Any interface default method should be invoked by:

  1. Finding the MethodHandles.Lookup through MethodHandles.lookup().in(declaringClass),
  2. Get a MethodHandle bypassing any overriding methods through .unreflectSpecial(method, declaringClass), and,
  3. Invoke the method on the proxy with .bindTo(proxy).invokeWithArguments(argv)

不幸的是,如果声明类对调用方不是“私有可访问的”(大多数情况下),从而导致:

Caused by: java.lang.IllegalAccessException: no private access for invokespecial: interface package1.SomeInterface, from package1.SomeInterface/public
    at java.lang.invoke.MemberName.makeAccessException(MemberName.java:850)
    at java.lang.invoke.MethodHandles$Lookup.checkSpecialCaller(MethodHandles.java:1572)
    at java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(MethodHandles.java:1231)
    at package2.InvocationHandlerImpl.invoke(InvocationHandlerImpl.java:59)

实际的Java 8解决方案是:

    @Override
    public Object invoke(Object proxy,
                         Method method, Object[] argv) throws Throwable {
        Object result = null;
        Class<?> declaringClass = method.getDeclaringClass();

        if (method.isDefault()) {
            Constructor<MethodHandles.Lookup> constructor =
                MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);

            constructor.setAccessible(true);

            result =
                constructor.newInstance(declaringClass)
                .in(declaringClass)
                .unreflectSpecial(method, declaringClass)
                .bindTo(proxy)
                .invokeWithArguments(argv);
        } else {
            /*
             * Logic to calculate result.
             */
        }

        return result;
    }

这在Java 9+中不起作用。 在Java 9及更高版本中,解决方案应基于MethodHandles。Lookup。findSpecial()和/或MethodHandles。privateLookupIn()。

from: https://dev.to//allenball/adding-support-to-java-invocationhandler-implementations-for-interface-default-methods-h64

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值