Skip to content

Commit d65a1e5

Browse files
committed
[Java.Interop] JavaException.InnerException should elide Proxies.
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.
1 parent 3398a48 commit d65a1e5

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

src/Java.Interop/Java.Interop/JavaException.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ static string _GetMessage (JniReferenceSafeHandle handle)
142142
return JniEnvironment.Strings.ToString (s, JniHandleOwnership.Transfer);
143143
}
144144

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

152152
string _GetJavaStack (JniReferenceSafeHandle handle)

src/Java.Interop/Tests/Java.Interop/JavaExceptionTests.cs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,43 @@ static JniLocalReference CreateThrowable (JniType type, string message)
5050

5151
static void SetThrowableCause (JniType type, JniLocalReference outer, string message)
5252
{
53-
var i = type.GetInstanceMethod ("initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
5453
using (var cause = CreateThrowable (type, message)) {
55-
i.CallVirtualObjectMethod (outer, new JValue (cause))
56-
.Dispose ();
54+
SetThrowableCause (type, outer, cause);
55+
}
56+
}
57+
58+
static void SetThrowableCause (JniType type, JniLocalReference outer, JniReferenceSafeHandle inner)
59+
{
60+
var i = type.GetInstanceMethod ("initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
61+
i.CallVirtualObjectMethod (outer, new JValue (inner))
62+
.Dispose ();
63+
}
64+
65+
[Test]
66+
public void InnerExceptionIsNotAProxy ()
67+
{
68+
using (var t = new JniType ("java/lang/Throwable")) {
69+
var outer = CreateThrowable (t, "Outer Exception");
70+
var ex = new InvalidOperationException ("Managed Exception!");
71+
var exp = CreateJavaProxyThrowable (ex);
72+
SetThrowableCause (t, outer, exp.SafeHandle);
73+
using (var e = new JavaException (outer, JniHandleOwnership.Transfer)) {
74+
Assert.IsNotNull (e.InnerException);
75+
Assert.AreSame (ex, e.InnerException);
76+
}
77+
exp.Dispose ();
5778
}
5879
}
80+
81+
static JavaException CreateJavaProxyThrowable (Exception value)
82+
{
83+
var JavaProxyThrowable_type = typeof(JavaObject)
84+
.Assembly
85+
.GetType ("Java.Interop.JavaProxyThrowable", throwOnError :true);
86+
var proxy = (JavaException) Activator.CreateInstance (JavaProxyThrowable_type, value);
87+
proxy.RegisterWithVM ();
88+
return proxy;
89+
}
5990
}
6091
}
6192

0 commit comments

Comments
 (0)