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:
- Finding the
MethodHandles.Lookup
throughMethodHandles.lookup().in(declaringClass)
, - Get a
MethodHandle
bypassing any overriding methods through.unreflectSpecial(method, declaringClass)
, and, - 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()。