Исходное имя класса прокси (без ручной манипуляции с строкой)

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