2010-07-27 14 views

Respuesta

20

Puede obtener el InvocationHandler con el que se creó el proxy, llamando Proxy.getInvocationHandler(proxy)

Tenga en cuenta que en el caso de java.lang.reflect.Proxy no hay clases subyacente per se. El proxy se define por:

  • interfaz (s)
  • manejador invocación

Y la clase envueltos por lo general se pasa al controlador de invocación concreta.

+1

Gracias. ¿Qué me consigue el controlador de invocación? Tengo un proxy, pero quiero el nombre de clase del objeto que está implementando la interfaz desde la que está construido el proxy. Estoy pensando que no es posible ... – blank

+0

No hay otro objeto que el proxy. El controlador de invocación es responsable de enviar la llamada – Bozho

10

Bueno, una instancia Proxy no será una instancia de java.lang.reflect.Proxyper se. Por el contrario, será una instancia de una subclase de java.lang.reflect.Proxy.

De todos modos, la forma de obtener el nombre real clases de proxy es:

Proxy proxy = ... 
System.err.println("Proxy class name is " + proxy.getClass().getCanonicalName()); 

Sin embargo, no se puede obtener el nombre de la clase que el proxy es un proxy para, debido a que:

  1. que las interfaces de proxy no clases, y
  2. un proxy puede ser un indicador de múltiples interfaces

Sin embargo, al mirar el código fuente de la clase ProxyGenerator, parece que las interfaces se registran en la clase proxy generada como las interfaces de la clase. Por lo tanto, debería poder obtenerlos en tiempo de ejecución a través del objeto de clases de proxy Class; p.ej.

Class<?>[] classes = proxy.getClass().getInterfaces(); 

(Nota: No he intentado esto ...)

+1

'proxy.getClass(). GetInterfaces()' funciona perfecto! – StrikeW

15

He encontrado una buena solución en this site (ahora archivada):

@SuppressWarnings({"unchecked"}) 
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception { 
    if (AopUtils.isJdkDynamicProxy(proxy)) { 
    return (T) ((Advised)proxy).getTargetSource().getTarget(); 
    } else { 
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class 
    } 
} 

Uso

@Override 
protected void onSetUp() throws Exception { 
    getTargetObject(fooBean, FooBeanImpl.class).setBarRepository(new MyStubBarRepository()); 
} 
+0

El argumento "targetClass" no se usa :) –

+0

Sí, solo es para el tipo de conversión – Sllouyssgort

+1

En ese caso, ¿no sería mejor usarlo realmente para enviar contenido, en lugar de suprimir las advertencias, por ej. 'targetClass.cast (proxy)'? De esta forma, se garantiza que obtendrás un objeto de ese tipo, mientras que en el otro caso, debido a la eliminación del tipo, la conversión puede no producirse según el patrón de uso. –

4

Aquí estaba la solución que utilizamos con mi equipo (necesitamos el nombre de la clase detrás del proxy):

if (getTargetName(yourBean) ...) { 

} 

Con este pequeño ayudante:

private String getTargetName(final Object target) { 

    if (target == null) { 
     return ""; 
    } 

    if (targetClassIsProxied(target)) { 

     Advised advised = (Advised) target; 

     try { 

      return advised.getTargetSource().getTarget().getClass().getCanonicalName(); 
     } catch (Exception e) { 

      return ""; 
     } 
    } 

    return target.getClass().getCanonicalName(); 
} 

private boolean targetClassIsProxied(final Object target) { 

    return target.getClass().getCanonicalName().contains("$Proxy"); 
} 

espero que ayude!

2

Usted puede utilizar el siguiente código para recuperar la información (ArrayUtils es de Apache Commons Lang) sobre manejador de invocación y las interfaces del servidor actual: resultado

String.format("[ProxyInvocationHandler: %s, Interfaces: %s]", 
    Proxy.getInvocationHandler(proxy).getClass().getSimpleName(), 
    ArrayUtils.toString(proxy.getClass().getInterfaces())); 

Ejemplo:

[ProxyInvocationHandler: ExecuteProxyChain, Interfaces: {interface com.example.api.CustomerApi}]} 
0

En primer lugar, java.lang.reflect.Proxy funciona solo en interfaces. El marco crea una clase descendiente que implementa la (s) interfaz (es) pero extiende java.lang.reflect.Proxy en lugar de una clase de aplicación que puede ser de su interés. No hay herencia de clases múltiples en Java moderno (2016).

En mi caso, el depurador muestra que el objeto de interés está en el campo obj en el controlador de invocación del objeto proxy.

Object handler = Proxy.getInvocationHandler(somethingProxied); 
    Class handlerClass = handler.getClass(); 
    Field objField = handlerClass.getDeclaredField("obj"); 
    objField.setAccessible(true); 
    Object behindProxy = objField.get(handler); 

Tendrá que catch() dos excepciones: NoSuchFieldException y IllegalAccessException.

He encontrado que es útil para imprimir la lista de campos de campos declarados de la cláusula catch():

... 
} catch (NoSuchFieldException nsfe) { 
    nsfe.printStackTrace(); 

    Object handler = Proxy.getInvocationHandler(somethingProxied); 
    Class handlerClass = handler.getClass(); 
    for (Field f : handlerClass.getDeclaredFields()) { 
     f.setAccessible(true); 
     String classAndValue = null; 
     try { 
      Object v = f.get(handler); 
      classAndValue= "" + (v == null ? "" : v.getClass()) + " : " + v; 
     } catch (IllegalAccessException iae) { 
      iae.printStackTrace(); 
     } 
     System.out.println(" field: " + f.getName() + " = " + classAndValue+ ";"); 
    } 
... 
} 

Tenga en cuenta que los diferentes marcos utilizan diferentes servidores proxy e incluso diferentes técnicas de proxy. La solución que funcionó para mí puede no ser aplicable en su caso. (Definitivamente no funcionará para los proxis de Javassist o Hibernate.)

Cuestiones relacionadas