Javassist: cómo crear de proxy de proxy?
Pregunta
Estoy creando apoderados con ProxyFactory
javassist. Al crear un único proxy todo funciona bien.
Sin embargo, al pasar un objeto proxy al mecanismo de proxy, falla con
javassist.bytecode.DuplicateMemberException: método duplicado: SetHandler en com.mypackage.Bean _ $$ _ javassist_0 _ $$ _ javassist_1
Estoy creando los proxies con esto:
public Object createProxiedInstance(Object originalInstance) throws Exception {
Class<?> originalClass = instance.getClass();
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(originalClass);
factory.setHandler(new MethodHandler() {..});
Class<T> proxyClass = factory.createClass();
return proxyClass.newInstance();
}
Entonces, ¿cómo puedo crear proxies de proxy?
Actualización: Los problemas reales es que cada uno de los implementos de proxy la ProxyObject
que define método setHandler(..)
. Por lo que el segundo proxy está tratando de redefinir el método, en lugar de anular en la subclase.
Solución
El problema era (en realidad, es lo mismo con CGLIB - Yo probé usando Commons-proxy) que no debería tratar de crear una clase de proxy de la clase de proxy. El segundo proxy debería volver a ser de la clase original. Por lo que añadir la siguiente línea resuelve el problema:
if (instance instanceof ProxyObject) {
originalClass = originalClass.getSuperclass();
}
Y un consejo - si se puede usar algún tipo de interceptores (como los definidos en Commons-proxy), hacerlo en lugar de utilizar múltiples servidores proxy
.Otros consejos
Es una respuesta bastante tarde, pero todavía puede estar interesado en saber esto:
proxies Javassist se implementan con bastante ingenuidad. En el código anterior, Javassist siempre va a crear una clase de proxy con los métodos siguientes:
- método A para cualquier método reemplazable de la clase base
- dos métodos para (a) obtener un controlador de proxy (
getHandler
) y (b) establecer un controlador de proxy (setHandler
)
Los nombres de los dos últimos métodos están codificados por Javassist y representada por la interfaz de ProxyObject
. Si ahora crear una clase de proxy de una clase de proxy, Javassist programaría la creación de métodos de ProxyObject
dos veces. Una vez por la primera condición y una vez por la segunda condición.
Se puede evitar esto mediante el establecimiento de un MethodFilter
que especifica que no anulan los métodos del ProxyObject
tal que javassist no haría sino crear los métodos de la segunda condición. Sin embargo, esto implicaría que ya no se podía establecer un ProxyObject
para el proxy súper clase sin tener que acceder directamente al campo correspondiente a través de la reflexión. Por lo tanto, su enfoque es probablemente el más limpio.
cglib define devoluciones de llamada por clase y no por ejemplo de tal manera que este problema con cglib es ligeramente diferente pero los resultados en otro conflicto.
Sin embargo, si desea crear clases de proxy que no sufren estas deficiencias, que podría estar interesado en mi biblioteca Byte de amigos que escribí después de conseguir trabajo frustrado con cglib y javassist cuando se trabaja en casos de esquina. Si está trabajando con la generación de código en tiempo de ejecución espero que podría ayudarle a ofrecer una cierta flexibilidad que las otras bibliotecas carecen.