Alternative a java.lang.reflect.Proxy per creare proxy di classi astratte (piuttosto che interfacce)

StackOverflow https://stackoverflow.com/questions/3291637

  •  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
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top