2013-01-24 7 views
10

In Java, come si ottiene l'oggetto classe originale e/o il nome classe di un proxy Java EE (CDI)?Nome classe originale di un proxy (senza manipolazione manuale delle stringhe)

Quando si utilizza getName() su un'istanza di proxy, il nome restituito è qualcosa di simile

com.company.employeemgmt.EmployeeManager$Proxy$_$$_WeldSubclass 

C'è qualche functionaliy in Java SE (7) o EE (6) che restituirà sia l'istanza originale di classe unproxied o il suo nome?

Ho bisogno:

com.company.employeemgmt.EmployeeManager 

Naturalmente, si potrebbe semplicemente usare la manipolazione di stringhe, ma vorrei sapere se tale funzionalità è già su Java (EE) -inbuilt.

ho già trovato java.reflect.Proxy, che ho potuto utilizzare per rilevare i proxy:

public static void doSomething(Class<? implements Serializable> managerClass) 
{ 
    if (Proxy.isProxyClass(managerClass)) 
    { 
     // unproxy how? 
     managerClass = managerClass.getUnproxiedClass(); 
    } 

    // delegate 
    doSomething(managerClass.getName()); 
} 


public static void doSomething(String prefix) 
{ 
    // do real work 
    ... 
} 

..., ma come si farebbe dereferenziare classe originale?

Aggiornamento:

Il trucco sarebbe quello di accedere MyUtil.doSomething(EmployeeManager.class) (o MyUtil.doSomething(EmployeeManager.class.getName())), ma vorrei usare/pass MyUtil.doSomething(this.getClass()) (o MyUtil.doSomething(this.getClass().getName())) da tutti i client come questo codice può essere copiato in giro senza modifiche manuali .

+0

Hai provato managerClass.getDeclaringClass() o managerClass.getEnclosingClass()? – jdb

+0

Entrambi restituiscono null. – Kawu

+0

Niente di quello che fai qui sarebbe portatile o stabile. Il proxy è in realtà solo "correlato" all'altra classe.Il CDI non stabilisce quale tecnologia viene utilizzata per il proxy o alcun modo per ottenere da un proxy i dettagli della classe del bean gestito (sebbene sia possibile iniziare con l'API BeanManager e lavorare avanti anziché indietro da un oggetto) – covener

risposta

4

Dipende dallo. È possibile ottenere il InvocationHandler per un proxy utilizzando Proxy.getInvocationHandler(manager). Ahimè, InvocationHandler è un'interfaccia con un solo metodo invoke e senza nessuna caratteristica che ti permetta di ottenere una classe di destinazione; tutto dipende dall'implementazione.

A titolo di esempio il framework web servcie CXF ha un Client e utilizza un ClientProxy come un gestore di invocazione associata, è possibile ottenere il Cliente in quanto tale:

ClientProxy handler = (ClientProxy)Proxy.getInvocationHandler(proxiedObject); 
Client client = handler.getClient(); 

Per aggiungere la beffa al danno, sembra che la WeldInvocationHandler che probabilmente stai usando semplicemente delega la chiamata a un org.jboss.wsf.spi.invocation.InvocationHandler che memorizza il suo delegato in un campo privato. Quindi è necessario fare un po 'di magia con la riflessione per scoprire la classe reale dell'oggetto target.

2

Poiché la classe proxy eredita dalla classe originale, penso che è possibile ottenere la classe originale ottenendo la superclasse proxy.

0

Poiché il proxy implementa le interfacce proxy, è possibile utilizzare Class<?>[] Class.getInterfaces() per individuare le classi proxy.

private Class<?> findProxiedClass(Object proxiedObject) { 

    Class<?> proxiedClass = proxiedObject.getClass(); 

    if (proxiedObject instanceof Proxy) { 
     Class<?>[] ifaces = proxiedClass.getInterfaces(); 
     if (ifaces.length == 1) { 
      proxiedClass = ifaces[0]; 
     } else { 
      // We need some selection strategy here 
      // or return all of them 
      proxiedClass = ifaces[ifaces.length - 1]; 
     } 
    } 
    return proxiedClass; 
} 

test con

@Test 
public void testProxies() { 

    InvocationHandler handler = new InvocationHandler() { 
     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) 
       throws Throwable { 
      return null; 
     } 
    }; 

    RandomAccess proxiedIface = (RandomAccess) Proxy.newProxyInstance(
      RandomAccess.class.getClassLoader(), 
      new Class[] { RandomAccess.class }, 
      handler); 

    Assert.assertEquals(RandomAccess.class, findProxiedClass(proxiedIface)); 
    Assert.assertEquals(Object.class, findProxiedClass(new Object())); 
}