Исходное имя класса прокси (без ручной манипуляции с строкой)
В 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
...
}
..., но как бы вы разыменовали исходный класс?
Update:
Трюк будет заключаться в доступе к MyUtil.doSomething( EmployeeManager.class )
(или MyUtil.doSomething( EmployeeManager.class.getName() )
), но я бы хотел использовать /pass MyUtil.doSomething( this.getClass() )
(или MyUtil.doSomething( this.getClass().getName() )
) для всех клиентов, так как этот код можно скопировать без ручных изменений.
Ответы
Ответ 1
Это зависит. Вы можете получить InvocationHandler для прокси-сервера, используя Proxy.getInvocationHandler(менеджер ). Увы, InvocationHandler - это интерфейс только с одним методом invoke
и без функции, позволяющей получить целевой класс; все зависит от реализации.
В качестве примера структура веб-серфинга CXF имеет Client и использует ClientProxy в качестве связанного обработчика вызовов, вы можете получить Клиент как таковой:
ClientProxy handler = (ClientProxy)Proxy.getInvocationHandler(proxiedObject);
Client client = handler.getClient();
Чтобы добавить оскорбление к травме, кажется, что WeldInvocationHandler, который вы, вероятно, используете, просто делегирует вызов org.jboss.wsf.spi.invocation.InvocationHandler, что он сохраняет свой делегат в закрытом поле. Таким образом, вам нужно сделать довольно волшебство с отражением, чтобы узнать фактический класс целевого объекта.
Ответ 2
Поскольку класс прокси наследуется от исходного класса, я думаю, что вы можете получить исходный класс, получив прокси-суперкласс.
Ответ 3
Поскольку proxy реализует интерфейсы, которые он использует, вы можете использовать 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()));
}