Skip to content

Commit

Permalink
[Java.Interop] JavaException.InnerException should elide Proxies.
Browse files Browse the repository at this point in the history
Fixes: #1

JavaProxyThrowable is an internal type, and as such it shouldn't
"leak" if at all possible, e.g. if someone creates a
java.lang.Throwable in which the `cause` is a managed exception type
such as InvalidOperationException.

Previously, Exception.InnerException would have been the
JavaProxyThrowable, as JavaException._GetCause() would lookup a
JavaException instance. Returning a JavaProxyThrowable is ~useless;
it's not a public API, and thus nothing useful can be done with it
(short of resorting to Reflection).

Fix JavaException._GetCause() so that it instead uses
JavaVM.GetExceptionForThrowable(), which automatically "unwraps"
JavaProxyThrowable instances to return the wrapped Exception.
  • Loading branch information
jonpryor committed Apr 7, 2015
1 parent 3398a48 commit d65a1e5
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/Java.Interop/Java.Interop/JavaException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ static string _GetMessage (JniReferenceSafeHandle handle)
return JniEnvironment.Strings.ToString (s, JniHandleOwnership.Transfer);
}

static JavaException _GetCause (JniReferenceSafeHandle handle)
static Exception _GetCause (JniReferenceSafeHandle handle)
{
var m = _members.InstanceMethods.GetMethodID ("getCause\u0000()Ljava/lang/Throwable;");
var e = m.CallVirtualObjectMethod (handle);
return JniEnvironment.Current.JavaVM.GetObject<JavaException> (e, JniHandleOwnership.Transfer);
return JniEnvironment.Current.JavaVM.GetExceptionForThrowable (e, JniHandleOwnership.Transfer);
}

string _GetJavaStack (JniReferenceSafeHandle handle)
Expand Down
37 changes: 34 additions & 3 deletions src/Java.Interop/Tests/Java.Interop/JavaExceptionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,43 @@ static JniLocalReference CreateThrowable (JniType type, string message)

static void SetThrowableCause (JniType type, JniLocalReference outer, string message)
{
var i = type.GetInstanceMethod ("initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
using (var cause = CreateThrowable (type, message)) {
i.CallVirtualObjectMethod (outer, new JValue (cause))
.Dispose ();
SetThrowableCause (type, outer, cause);
}
}

static void SetThrowableCause (JniType type, JniLocalReference outer, JniReferenceSafeHandle inner)
{
var i = type.GetInstanceMethod ("initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
i.CallVirtualObjectMethod (outer, new JValue (inner))
.Dispose ();
}

[Test]
public void InnerExceptionIsNotAProxy ()
{
using (var t = new JniType ("java/lang/Throwable")) {
var outer = CreateThrowable (t, "Outer Exception");
var ex = new InvalidOperationException ("Managed Exception!");
var exp = CreateJavaProxyThrowable (ex);
SetThrowableCause (t, outer, exp.SafeHandle);
using (var e = new JavaException (outer, JniHandleOwnership.Transfer)) {
Assert.IsNotNull (e.InnerException);
Assert.AreSame (ex, e.InnerException);
}
exp.Dispose ();
}
}

static JavaException CreateJavaProxyThrowable (Exception value)
{
var JavaProxyThrowable_type = typeof(JavaObject)
.Assembly
.GetType ("Java.Interop.JavaProxyThrowable", throwOnError :true);
var proxy = (JavaException) Activator.CreateInstance (JavaProxyThrowable_type, value);
proxy.RegisterWithVM ();
return proxy;
}
}
}

0 comments on commit d65a1e5

Please sign in to comment.