代理的原始类名(无需手动字符串操作)



在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()));
}

最新更新