Reputation: 637
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
Upvotes: 6
Views: 17374
Reputation: 75406
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.
Upvotes: 0
Reputation: 156
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
Upvotes: 10
Reputation: 1009
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.
Upvotes: 0
Reputation: 597224
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);
Upvotes: 3
Reputation: 14779
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
.
Upvotes: 1