2014-10-05 33 views
10

Avendo un proxy dinamico per un'interfaccia con metodi predefiniti, come posso richiamare un metodo predefinito? Usando qualcosa come defaultmethod.invoke(this, ...) hai appena chiamato il tuo gestore di chiamata proxy (che è in qualche modo corretto, perché non hai una classe di implementazione per questa interfaccia).Proxy dinamico Java8 e metodi predefiniti

Ho una soluzione alternativa che utilizza ASM per creare una classe che implementa l'interfaccia e che delega tali chiamate a un'istanza di questa classe. Ma questa non è una buona soluzione, soprattutto se il metodo predefinito chiama altri metodi di interfaccia (si ottiene un delegatore ping-pong). Il JLS è sorprendentemente in silenzio su questa domanda ...

Ecco un piccolo esempio di codice:

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

risposta

13

È possibile utilizzare il tipo MethodHandles nel proprio InvocationHandler. Questo codice viene copiato da 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

Questo funziona. Avevo bisogno di un altro suggerimento, l'oggetto proxy mi deve conoscere nel gestore di chiamata. Grazie mille! – Cfx

1

A Proxy implementa tutti i metodi sue interfacce supportate. Tutti invocano lo Proxy con.

A Proxy è destinato a delegare una chiamata a un'istanza reale. Il metodo default è già stato sostituito dal proxy e pertanto non può essere richiamato direttamente. Lo Proxy intercetterà tutte le chiamate e le passerà allo .

Avvolgere un'istanza reale dell'interfaccia nel proxy e delegare ad essa.

+0

Per eseguire il wrapping di un'istanza dell'interfaccia nel proxy e la delega ad esso è la mia soluzione corrente. Ma perché non esiste una classe che implementa l'interfaccia (e non conosco l'interfaccia fino al runtime, quindi il proxy ...) Ho bisogno di creare questo tramite la manipolazione del codice byte che è un enorme sovraccarico. È ancora più complicato, perché devo filtrare i metodi non predefiniti e restituirli al proxy. La mia domanda è: c'è solo una riflessione, la soluzione DynamicProxy JRE a questo? (senza ASM) – Cfx

0

ho trovato this article estremamente utile quando si cerca di capire il problema di riflessivo invocare un metodo di interfaccia di default su un proxy di tale interfaccia.

Problemi correlati