Alternativas a java.lang.reflect.Proxy para crear proxies de clases abstractas (en lugar de interfaces)

De acuerdo con la documentación :

[ java.lang.reflect. ] Proxy proporciona métodos estáticos para crear clases e instancias de proxy dynamic, y también es la superclase de todas las clases de proxy dynamic creadas por esos métodos.

El método newProxyMethod (responsable de generar los proxies dynamics) tiene la siguiente firma:

 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException 

Desafortunadamente, esto evita que uno genere un proxy dynamic que extienda una clase abstracta específica (en lugar de implementar interfaces específicas). Esto tiene sentido, considerando que java.lang.reflect.Proxy es “la superclase de todos los proxies dynamics”, lo que impide que otra clase sea la superclase.

Por lo tanto, ¿hay alguna alternativa a java.lang.reflect.Proxy que pueda generar proxies dynamics que hereden de una clase abstracta específica, redirigiendo todas las llamadas a los métodos abstractos al manejador de invocación?

Por ejemplo, supongamos que tengo una clase abstracta Dog :

 public abstract class Dog { public void bark() { System.out.println("Woof!"); } public abstract void fetch(); } 

¿Hay alguna clase que me permita hacer lo siguiente?

 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 

Se puede hacer usando Javassist (ver ProxyFactory ) o CGLIB .

El ejemplo de Adam usando el Javassist:

Yo (Adam Paynter) escribí este código 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(); 

Que produce esta salida:

 ¡Guau!
 Manejo de mock vacío público abstracto.Dog.fetch () a través del controlador de métodos

Lo que puede hacer en ese caso es tener un controlador de proxy que redirija las llamadas a los métodos existentes de su clase abstracta.

Usted, por supuesto, tendrá que codificarlo, sin embargo, es bastante simple. Para crear su Proxy, tendrá que darle un InvocationHandler . Luego, solo tendrá que verificar el tipo de método en el método invoke(..) de su controlador de invocación. Pero cuidado: tendrá que verificar el tipo de método con el objeto subyacente asociado a su controlador y no con el tipo declarado de su clase abstracta.

Si tomo como ejemplo su clase de perro, el método de invocación de su manejador de invocación puede verse así (con una subclase de perro asociada existente llamada … bueno … 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 ? } } 

Sin embargo, hay algo que me mantiene preguntándome: he hablado sobre un objeto de dog . Pero, como la clase Dog es abstracta, no puede crear instancias, por lo que tiene subclases existentes. Además, como revela una inspección rigurosa del código fuente del Proxy, puede descubrir (en Proxy.java:362) que no es posible crear un Proxy para un objeto Class que no represente una interfaz).

Entonces, aparte de la realidad , lo que quieres hacer es perfectamente posible.

    Intereting Posts