Alternative a java.lang.reflect.Proxy per creare proxy di classi astratte (piuttosto che interfacce)
-
18-09-2020 - |
Domanda
Secondo la documentazione:
[
java.lang.reflect.
]Proxy
Fornisce metodi statici per la creazione di classi e istanze di proxy dinamici, ed è anche la superclasse di tutte le classi di proxy dinamiche create da tali metodi.
IL newProxyMethod
metodo (responsabile della generazione delle proxy dinamiche) ha la seguente firma:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
Sfortunatamente, questo impedisce di generare un proxy dinamico that si estende una specifica classe astratta (piuttosto che implementazione interfacce specifiche).Questo ha senso, considerando java.lang.reflect.Proxy
è "la superclasse di tutti i proxy dinamici", impedendo così a un'altra classe di essere la superclasse.
Pertanto, esistono alternative a java.lang.reflect.Proxy
che può generare proxy dinamici che ereditare da una classe astratta specifica, reindirizzando tutte le chiamate a astratto metodi al gestore di invocazione?
Ad esempio, supponiamo di avere una classe astratta Dog
:
public abstract class Dog {
public void bark() {
System.out.println("Woof!");
}
public abstract void fetch();
}
Esiste un corso che mi permette di fare quanto segue?
Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);
dog.fetch(); // Will be handled by the invocation handler
dog.bark(); // Will NOT be handled by the invocation handler
Soluzione
Può essere fatto utilizzando Javassist (Vedere ProxyFactory
) O CGLIB.
L'esempio di Adam che utilizza Javassist:
Io (Adam Paynter) ho scritto questo codice usando Javassist:
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
new MethodFilter() {
@Override
public boolean isHandled(Method method) {
return Modifier.isAbstract(method.getModifiers());
}
}
);
MethodHandler handler = new MethodHandler() {
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
System.out.println("Handling " + thisMethod + " via the method handler");
return null;
}
};
Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();
Che produce questo output:
Woof! Handling public abstract void mock.Dog.fetch() via the method handler
Altri suggerimenti
Ciò che puoi fare in questo caso è avere un gestore proxy che reindirizzerà le chiamate ai metodi esistenti della tua classe astratta.
Ovviamente dovrai codificarlo, tuttavia è abbastanza semplice.Per creare il tuo Proxy, dovrai dargli un file InvocationHandler
.Dovrai quindi solo controllare il tipo di metodo nel file invocare(..)
metodo del gestore di invocazione.Ma attenzione:dovrai verificare il tipo del metodo rispetto all'oggetto sottostante associato al tuo gestore e non rispetto al tipo dichiarato della tua classe astratta.
Se prendo come esempio la tua classe dog, il metodo invoke del tuo gestore di invocazione Maggio assomiglia a questo (con una sottoclasse di cane associata esistente chiamata ..BENE ... dog
)
public void invoke(Object proxy, Method method, Object[] args) {
if(!Modifier.isAbstract(method.getModifiers())) {
method.invoke(dog, args); // with the correct exception handling
} else {
// what can we do with abstract methods ?
}
}
Tuttavia c'è qualcosa che mi fa riflettere:Ho parlato di a dog
oggetto.Ma, poiché la classe Dog è astratta, non puoi creare istanze, quindi hai sottoclassi esistenti.Inoltre, come rivela un'ispezione rigorosa del codice sorgente del proxy, potresti scoprire (in Proxy.java:362) che non è possibile creare un proxy per un oggetto classe che non rappresenta un'interfaccia).
Quindi, a parte il la realtà, quello che vuoi fare è perfettamente possibile.