blob: 5d7cb7d104110e842effc8308e76c2c38d4a9280 [file] [log] [blame]
h1. UndeclaredThrowableException
When two java interfaces are implemented by a proxy and those two interfaces declare the *same method* but with *different throws clauses* some very nasty side effects happen, namely you loose the ability to throw any checked exceptions that are not in the throws clause of both methods.
{code}
import junit.framework.TestCase;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
/**
* @version $Rev$ $Date$
*/
public class ExceptionTest extends TestCase {
public void test() throws Exception {
ClassLoader classLoader = this.getClass().getClassLoader();
Class[] interfaces = new Class[]{One.class, Two.class};
InvocationHandler h = new TestInvocationHandler();
Object proxy = java.lang.reflect.Proxy.newProxyInstance(classLoader, interfaces, h);
One one = (One) proxy;
try {
one.run(new CommonException());
} catch (CommonException e) {
// this will work
} catch(UndeclaredThrowableException u) {
Throwable t = u.getCause();
fail("Undeclared: "+t);
} catch(Throwable t){
fail("Caught: "+t);
}
try {
one.run(new OneException());
} catch (OneException e) {
} catch(UndeclaredThrowableException u) {
Throwable t = u.getCause();
fail("Undeclared: "+t); // This will always be the code that executes
} catch(Throwable t){
fail("Caught: "+t);
}
Two two = (Two) proxy;
try {
two.run(new CommonException());
} catch (TwoException e) {
} catch(UndeclaredThrowableException u) {
Throwable t = u.getCause();
fail("Undeclared: "+t); // This will always be the code that executes
} catch(Throwable t){
fail("Caught: "+t);
}
}
public static class CommonException extends Exception {
public CommonException() {
}
}
public static interface One {
void run(Object o) throws OneException, CommonException;
}
public static class OneException extends Exception {
public OneException() {
}
}
public static interface Two {
void run(Object o) throws TwoException, CommonException;
}
public static class TwoException extends Exception {
public TwoException() {
}
}
private static class TestInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw (Throwable)args[0];
}
}
}
{code}
h1. IllegalArgumentException
This one is less of a runtime problem as doing this will cause things to fail up front. When two java interfaces are implemented by a proxy and those two interfaces declare the *same method* but with *different return types* the VM proxy code will refuse to create a proxy at all. Take this code example:
{code}
import junit.framework.TestCase;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @version $Rev$ $Date$
*/
public class ReturnTest extends TestCase {
public void test() throws Exception {
ClassLoader classLoader = this.getClass().getClassLoader();
Class[] interfaces = new Class[]{ReturnTest.One.class, ReturnTest.Two.class};
InvocationHandler h = new ReturnTest.TestInvocationHandler();
Object proxy = java.lang.reflect.Proxy.newProxyInstance(classLoader, interfaces, h);
One one = (One) proxy;
try {
Object object = one.run(new ThingOne());
} catch (Throwable t) {
fail("Caught: " + t);
}
Two two = (Two) proxy;
try {
Object object = two.run(new ThingTwo());
} catch (Throwable t) {
fail("Caught: " + t);
}
}
public static interface One {
ThingOne run(Object o);
}
public static class ThingOne {
}
public static interface Two {
ThingTwo run(Object o);
}
public static class ThingTwo {
}
private static class TestInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return args[0];
}
}
}
{code}
Running this code will result in the following exception:
{noformat}
java.lang.IllegalArgumentException: methods with same signature run(java.lang.Object) but incompatible return types: [class ReturnTest$ThingOne, class ReturnTest$ThingTwo]
at sun.misc.ProxyGenerator.checkReturnTypes(ProxyGenerator.java:669)
at sun.misc.ProxyGenerator.generateClassFile(ProxyGenerator.java:420)
at sun.misc.ProxyGenerator.generateProxyClass(ProxyGenerator.java:306)
at java.lang.reflect.Proxy.getProxyClass(Proxy.java:501)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
at ReturnTest.test(ReturnTest.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32)
{noformat}