在Java中,如何获取Java EE(CDI)代理的原始类对象和/或类名?
在代理实例上使用 getName()
时,返回的名称类似于
com.company.employeemgmt.EmployeeManager$Proxy$_$$_WeldSubclass
Java SE (7) 或 EE (6) 中是否有一些函数将返回原始的、未代理的类实例或其名称?
我需要:
com.company.employeemgmt.EmployeeManager
当然,我可以简单地使用字符串操作,但我想知道这样的功能是否已经是Java-(EE)内置的。
我已经找到了java.reflect.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
...
}
...,但是您将如何取消引用原始类?
更新:
诀窍是访问MyUtil.doSomething( EmployeeManager.class )
(或MyUtil.doSomething( EmployeeManager.class.getName() )
),但我想从所有客户端使用/传递MyUtil.doSomething( this.getClass() )
(或MyUtil.doSomething( this.getClass().getName() )
),因为无需手动更改即可复制此代码。
由于代理类继承自原始类,我认为您可以通过获取代理超类来获取原始类。
这取决于。您可以使用 Proxy.getInvocationHandler(manager) 获取代理的 InvocationHandler。唉,InvocationHandler 是一个只有一个 invoke
方法的接口,没有允许您获取目标类的功能;这一切都取决于实施。
例如,CXF Web servcie 框架有一个客户端,并使用 ClientProxy 作为关联的调用处理程序,您可以按如下方式获取客户端:
ClientProxy handler = (ClientProxy)Proxy.getInvocationHandler(proxiedObject);
Client client = handler.getClient();
雪上加霜的是,您可能正在使用的 WeldInvocationHandler 似乎只是将调用委托给 org.jboss.wsf.spi.invocation.InvocationHandler,它将委托存储在私有字段中。因此,您需要使用反射来执行相当多的魔术,以找出目标对象的实际类。
由于代理实现了它代理的接口,因此您可以使用Class<?>[] Class.getInterfaces()
找出代理类。
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
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()));
}