如何在Java中创建接口的代理?

发布于 2024-09-26 03:09:41 字数 1473 浏览 10 评论 0原文

如何在不创建实现接口的类的情况下为接口创建代理?

我有一个具体的例子:我有一个接口,联系人,需要创建一个充当联系人的代理对象。该代理对象将用于运行一些 TestNG 测试。

我尝试过使用 JDK 方法,但只能找到需要实际实现该接口的示例。

我还发现 jasssist 可能会帮助我解决这个问题,并尝试实现一个简单的示例,该示例似乎一直有效,直到出现内存不足错误。这是我正在做的事情的一个片段:

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() 方法的参数将是一个接口。

谢谢

How can one create a proxy for an interface without creating a class that implements it?

I have a concrete example: I have an interface, Contact, and need to create a proxy object that acts as a Contact. This proxy object will be used for running some TestNG tests.

I have tried using the JDK approach but could find only examples that needed an actual implementation of that interface.

I also found that jasssist may help me in this problem and tried implementing a simple example that seems to be working until I get an Out of Memory error. Here is a snippet of what I am doing:

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

Remember that the parameter of the createMock() method will be an interface.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

筱武穆 2024-10-03 03:09:42

exampledepot 在 http://exampledepot.8waytrips.com/egs/java.lang.reflect/ProxyClass.html

您只需为 invoke 提供功能(对象代理,方法 m,Object[] args) 在您自己的代码中。


编辑:根据评论,您不需要的类似乎是接口类,而不是实现类。在这种情况下,就没有办法绕过字节码操作。您可能想查看包含代码片段编译器的 Javassist。

Exampledepot has a simple snippet for how to create an interface proxy based on java.lang.reflect.proxy at http://exampledepot.8waytrips.com/egs/java.lang.reflect/ProxyClass.html

You just need to provide functionality for the invoke(Object proxy, Method m, Object[] args) in your own code.


EDIT: Based on comments it appears that the class you do not want is the interface class, not the implementation class. In that case there is no way around byte code manipulation. You may want to look at Javassist which contains a snippet compiler.

梦行七里 2024-10-03 03:09:41

您可以使用java.lang.reflect.ProxynewProxyInstance方法。
例如:

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

iClazz 是接口的类,YourInvocalHandlerjava.lang.reflect.InvocalHandler 的实例

You can use the method newProxyInstance of java.lang.reflect.Proxy.
Ex:

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

iClazz is the class of your interface and YourInvocationHandler is an instance of java.lang.reflect.InvocationHandler

打小就很酷 2024-10-03 03:09:41

commons-proxy 旨在简化任务。

您想要的是一个调用者代理(没有目标对象)。因此您可以使用:

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

并且您的 invoker 必须实现 Invoker 接口,其 invoke 方法将在每次方法调用时调用。 (此处“调用”一词的 4 倍)

请注意,commons-proxy 使用首选的底层代理机制 - 在上面的示例中它是 javassist。


但是,您似乎需要代理来进行模拟目的。使用 mockito 就这么简单:

YourInterface yourMock = mock(YourInterface.class);
when(yourMock.someMethod()).thenReturn(yourPreferredResult);

commons-proxy aims at simplifying the task.

What you want is an invoker proxy (without a target object). So you can use:

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

And your invoker must implement the Invoker interface, whose invoke method will be called on each method invocation. (4 times the word "invoke" here)

Note that commons-proxy uses the preferred underlying proxying mechanism - in the above example it's javassist.


However, you seem to need the proxy for mocking purposes. With mockito this is as easy as:

YourInterface yourMock = mock(YourInterface.class);
when(yourMock.someMethod()).thenReturn(yourPreferredResult);
非要怀念 2024-10-03 03:09:41

如果您只对模拟感兴趣,我建议使用框架。

EasyMock ( http://easymock.org/ ) 或 JMock ( http://www.jmock.org/ )可能适合。

要自己创建代理,您可以使用java.lang.reflect.Proxy类。

If you are only interesting in mocking I would suggest to use a framework.

EasyMock ( http://easymock.org/ ) or JMock ( http://www.jmock.org/ ) might fit.

To create a proxy yourself you can use the class java.lang.reflect.Proxy.

述情 2024-10-03 03:09:41

在您的代码中,我执行了以下操作

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

,得到了以下结果

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

这是您想要的吗?
如您所见,OutOfMemory 是由对您的调用的递归调用产生的。

In your code i did the following

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

and i got the following result

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

Is this what did you wanted?
As you can see the OutOfMemory was produced by a recursive call to your invoke.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文