2014-10-05 14 views
10

Posiadanie dynamicznego serwera proxy dla interfejsu z domyślnymi metodami, w jaki sposób wywołać metodę domyślną? Używając czegoś takiego jak defaultmethod.invoke(this, ...) po prostu otrzymujesz wywołanie procedury wywołania serwera proxy (co jest jakoś poprawne, ponieważ nie masz klasy implementującej dla tego interfejsu).Java8 dynamiczne proxy i domyślne metody

Mam obejście używające ASM do utworzenia klasy implementującej interfejs i delegowania takich wywołań do instancji tej klasy. Ale to nie jest dobre rozwiązanie, zwłaszcza jeśli domyślna metoda wywoła inne metody interfejsu (otrzymasz ping-ponga). JLS jest zaskakująco cichy o tym mowa ...

Oto mały przykład kodu:

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; 
    } 
} 

Odpowiedz

13

Możesz użyć typu MethodHandles w swoim InvocationHandler. Ten kod jest kopiowany z 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

To działa. Potrzebowałem jeszcze jednej podpowiedzi, obiekt proxy musi mnie znać w module obsługi wywołań. Dziękuję Ci bardzo! – Cfx

1

Proxy implementuje wszystkie metody swoich obsługiwanych interfejsów. Wszystkie one wywołują InvocationHandlerProxy został utworzony za pomocą.

A Proxy służy do delegowania wywołania do rzeczywistej instancji. Metoda default została już zastąpiona przez serwer proxy i dlatego nie można jej wywołać bezpośrednio. Proxy przechwyci wszystkie połączenia i przekaże je do InvocationHandler.

Owiń rzeczywistą instancję inteface w proxy i deleguj do niego.

+0

Zawijanie wystąpienia interfejsu w proxy i delegowanie do niego jest moim bieżącym obejściem. Ale ponieważ nie ma klasy implementującej interfejs (i nie znam interfejsu do czasu wykonania, dlatego proxy ...) muszę go utworzyć poprzez manipulację kodami bajtowymi, co jest ogromnym przeciążeniem. Jest to jeszcze bardziej skomplikowane, ponieważ muszę odfiltrować inne niż domyślne metody i przekazać je do serwera proxy. Moje pytanie brzmi: czy istnieje rozwiązanie tylko do refleksji, DynamicProxy JRE? (bez ASM) – Cfx

0

znalazłem this article niezwykle pomocne, gdy próbuje zrozumieć kwestię refleksyjnie wywoływanie domyślnej metody interfejsu na pełnomocnika tego interfejsu.

Powiązane problemy