Как создать прокси интерфейса в Java? - PullRequest
4 голосов
/ 05 октября 2010

Как можно создать прокси для интерфейса, не создавая класс, который его реализует?

У меня есть конкретный пример: у меня есть интерфейс, контакт, и мне нужно создать прокси-объект, который действует как контакт. Этот прокси-объект будет использоваться для запуска некоторых тестов TestNG.

Я пытался использовать подход JDK, но смог найти только примеры, которые требовали фактической реализации этого интерфейса.

Я также обнаружил, что jasssist может помочь мне в этой проблеме, и попытался реализовать простой пример, который, кажется, работает, пока я не получу ошибку Out of Memory. Вот фрагмент того, что я делаю:

import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory

protected final T createMock(final Class<T> clazz) {
    final ProxyFactory factory = new ProxyFactory();
    factory.setInterfaces(new Class[] { clazz });
    factory.setFilter(new MethodFilter() {
        public final boolean isHandled(final Method m) {
            // ignore finalize()
            return !m.getName().equals("finalize");
        }
    });

    final MethodHandler handler = createDefaultMethodHandler();
    try {
        return (T) factory.create(new Class<?>[0], new Object[0], handler);
    } catch (final Exception e) {
        e.printStackTrace();
    }
    return null;
}
private MethodHandler createDefaultMethodHandler() {
    return new MethodHandler() {
        public final Object invoke(final Object self,
                final Method thisMethod, final Method proceed,
                final Object[] args) throws Throwable {
            System.out.println("Handling " + thisMethod
                    + " via the method handler");
            return thisMethod.invoke(self, args);
        }
    };
}

Помните, что параметром метода createMock () будет интерфейс.

Спасибо

Ответы [ 5 ]

8 голосов
/ 19 сентября 2012

Вы можете использовать метод newProxyInstance из java.lang.reflect.Proxy. Пример:

    Proxy.newProxyInstance(iClazz.getClassLoader(),
        new Class[]{iClazz},
        new YourInvocationHandler())

iClazz - это класс вашего интерфейса, а YourInvocationHandler - это экземпляр java.lang.reflect.InvocationHandler

.
2 голосов
/ 05 октября 2010

commons-proxy имеет целью упростить задачу.

То, что вы хотите, это прокси-сервер-вызывающий (без целевого объекта).Таким образом, вы можете использовать:

ProxyFactory factory = new JavassistProxyFactory();
Object result = 
      factory.createInvokerProxy(invoker, new Class[] {YourInterface.class});

И ваш invoker должен реализовывать интерфейс Invoker, чей метод invoke будет вызываться при каждом вызове метода.(Здесь в 4 раза больше слова "invoke")

Обратите внимание, что commons-proxy использует предпочтительный базовый механизм прокси - в приведенном выше примере это javassist.


Однако вам, похоже, нужнопрокси для насмешливых целей.С mockito это так же просто, как:

YourInterface yourMock = mock(YourInterface.class);
when(yourMock.someMethod()).thenReturn(yourPreferredResult);
1 голос
/ 05 октября 2010

Если вас интересует только насмешка, я бы предложил использовать фреймворк.

Может подходить EasyMock (http://easymock.org/) или JMock (http://www.jmock.org/).

Для создания прокси вы можете использовать класс java.lang.reflect.Proxy.

0 голосов
/ 01 ноября 2010

В вашем коде я сделал следующее

//              return thisMethod.invoke(self, args);
            return null;

и я получил следующий результат

Handling public abstract void org.rege.instruments.IPerson.setName(java.lang.String) via the method handler

Это то, что вы хотели? Как вы можете видеть, OutOfMemory был создан рекурсивным вызовом вашего вызова.

0 голосов
/ 05 октября 2010

Exampledepot имеет простой фрагмент для того, как создать прокси интерфейса на основе java.lang.reflect.proxy в http://exampledepot.8waytrips.com/egs/java.lang.reflect/ProxyClass.html

Вам просто нужно предоставить функциональность для invoke(Object proxy, Method m, Object[] args) в вашем собственном коде.


РЕДАКТИРОВАТЬ: Судя по комментариям, вам не нужен класс интерфейс , а не класс реализация . В этом случае нет способа обойти манипулирование байтовым кодом. Возможно, вы захотите взглянуть на Javassist, который содержит компилятор сниппета.

...