2014-10-05 46 views
10

爲具有默認方法的接口提供動態代理,如何調用默認方法?通過使用諸如defaultmethod.invoke(this, ...)之類的東西,你只需要調用你的代理調用處理程序(這是正確的,因爲你沒有這個接口的實現類)。Java8動態代理和默認方法

我有一個解決方法,使用ASM來創建一個實現接口的類,並將此類調用委託給此類的一個實例。但是這不是一個好的解決方案,特別是如果默認方法調用其他接口方法(你會得到一個委託人乒乓)。該JLS是出奇的沉默,這個問題...

這裏一個小的代碼示例:

public class Java8Proxy implements InvocationHandler { 
    public interface WithDefaultMethod { 
     void someMethod(); 

     default void someDefaultMethod() { 
      System.out.println("default method invoked!"); 
     } 
    } 

    @Test 
    public void invokeTest() { 
     WithDefaultMethod proxy = (WithDefaultMethod) Proxy.newProxyInstance(
      WithDefaultMethod.class.getClassLoader(), 
      new Class<?>[] { WithDefaultMethod.class }, this); 
     proxy.someDefaultMethod(); 

    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 

     // assuming not knowing the interface before runtime (I wouldn't use a 
     // proxy, would I?) 
     // what to do here to get the line printed out? 

     // This is just a loop 
     // method.invoke(this, args); 

     return null; 
    } 
} 

回答

13

您可以在您的InvocationHandler中使用MethodHandles類型。此代碼複製自Zero Turnaround

Constructor<MethodHandles.Lookup> constructor; 
Class<?> declaringClass; 
Object result; 

if (method.isDefault()) { 
    declaringClass = method.getDeclaringClass(); 
    constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); 

    constructor.setAccessible(true); 

    result = constructor. 
     newInstance(declaringClass, MethodHandles.Lookup.PRIVATE). 
     unreflectSpecial(method, declaringClass). 
     bindTo(proxy). 
     invokeWithArguments(args); 

    return(result); 
} 
+0

這可以工作。我還需要一個提示,代理對象必須在調用處理程序中知道。非常感謝你! – Cfx 2014-10-06 07:59:47

1

一個Proxy實現了所有其支持的接口的方法。他們全部調用InvocationHandlerProxy創建。

A Proxy旨在將調用委託給實際實例。 default方法已被代理覆蓋,因此不能直接調用。 Proxy將攔截所有呼叫並將它們傳遞給InvocationHandler

將一個實際的inteface實例包裝在代理中並委託給它。

+0

將代理中的接口實例包裝並委派給它是我當前的解決方法。但是,因爲沒有實現接口的類(並且直到運行時才知道接口,因此代理...)我需要通過字節代碼操作來創建它,這是一個巨大的過載。它更加複雜,因爲我需要過濾掉非默認方法並讓它們傳遞迴代理。我的問題是:是否只有反射,DynamicProxy JRE解決方案? (不含ASM) – Cfx 2014-10-06 06:43:02

0

我發現this article非常有幫助想了解的反思調用該接口上的代理默認的接口方法的問題時。