|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object com.google.dexmaker.stock.ProxyBuilder<T>
public final class ProxyBuilder<T>
Creates dynamic proxies of concrete classes.
This is similar to the java.lang.reflect.Proxy
class, but works for classes instead of
interfaces.
java.util.Random
which will always return 4 when asked for integers, and which logs method calls to every method.
InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("nextInt")) { // Chosen by fair dice roll, guaranteed to be random. return 4; } Object result = ProxyBuilder.callSuper(proxy, method, args); System.out.println("Method: " + method.getName() + " args: " + Arrays.toString(args) + " result: " + result); return result; } }; Random debugRandom = ProxyBuilder.forClass(Random.class) .dexCache(getInstrumentation().getTargetContext().getDir("dx", Context.MODE_PRIVATE)) .handler(handler) .build(); assertEquals(4, debugRandom.nextInt()); debugRandom.setSeed(0); assertTrue(debugRandom.nextBoolean());
forClass(Class)
for the Class you wish to proxy. Call
handler(InvocationHandler)
passing in an InvocationHandler
, and then call
build()
. The returned instance will be a dynamically generated subclass where all method
calls will be delegated to the invocation handler, except as noted below.
The static method callSuper(Object, Method, Object...)
allows you to access the original
super method for a given proxy. This allows the invocation handler to selectively override some
methods but not others.
By default, the build()
method will call the no-arg constructor belonging to the class
being proxied. If you wish to call a different constructor, you must provide arguments for both
constructorArgTypes(Class[])
and constructorArgValues(Object[])
.
This process works only for classes with public and protected level of visibility.
You may proxy abstract classes. You may not proxy final classes.
Only non-private, non-final, non-static methods will be dispatched to the invocation handler. Private, static or final methods will always call through to the superclass as normal.
The Object.finalize()
method on Object
will not be proxied.
You must provide a dex cache directory via the dexCache(File)
method. You should take
care not to make this a world-writable directory, so that third parties cannot inject code into
your application. A suitable parameter for these output directories would be something like
this:
getApplicationContext().getDir("dx", Context.MODE_PRIVATE);
If the base class to be proxied leaks the this
pointer in the constructor (bad practice),
that is to say calls a non-private non-final method from the constructor, the invocation handler
will not be invoked. As a simple concrete example, when proxying Random we discover that it
inernally calls setSeed during the constructor. The proxy will not intercept this call during
proxy construction, but will intercept as normal afterwards. This behaviour may be subject to
change in future releases.
This class is not thread safe.
Method Summary | ||
---|---|---|
T |
build()
Create a new instance of the class to proxy. |
|
static Object |
callSuper(Object proxy,
Method method,
Object... args)
|
|
ProxyBuilder<T> |
constructorArgTypes(Class<?>... constructorArgTypes)
|
|
ProxyBuilder<T> |
constructorArgValues(Object... constructorArgValues)
|
|
ProxyBuilder<T> |
dexCache(File dexCache)
|
|
static
|
forClass(Class<T> clazz)
|
|
static InvocationHandler |
getInvocationHandler(Object instance)
Returns the proxy's InvocationHandler . |
|
ProxyBuilder<T> |
handler(InvocationHandler handler)
|
|
ProxyBuilder<T> |
parentClassLoader(ClassLoader parent)
Specifies the parent ClassLoader to use when creating the proxy. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Method Detail |
---|
public static <T> ProxyBuilder<T> forClass(Class<T> clazz)
public ProxyBuilder<T> parentClassLoader(ClassLoader parent)
If null, ProxyBuilder.class.getClassLoader()
will be used.
public ProxyBuilder<T> handler(InvocationHandler handler)
public ProxyBuilder<T> dexCache(File dexCache)
public ProxyBuilder<T> constructorArgValues(Object... constructorArgValues)
public ProxyBuilder<T> constructorArgTypes(Class<?>... constructorArgTypes)
public T build() throws IOException
UnsupportedOperationException
- if the class we are trying to create a proxy for is
not accessible.
IOException
- if an exception occurred writing to the dexCache
directory.
UndeclaredThrowableException
- if the constructor for the base class to proxy throws
a declared exception during construction.
IllegalArgumentException
- if the handler is null, if the constructor argument types
do not match the constructor argument values, or if no such constructor exists.public static InvocationHandler getInvocationHandler(Object instance)
InvocationHandler
.
IllegalArgumentException
- if the object supplied is not a proxy created by this class.public static Object callSuper(Object proxy, Method method, Object... args) throws SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
SecurityException
IllegalAccessException
InvocationTargetException
NoSuchMethodException
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |