Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Java.Interop] JavaException supports param override #1293

Merged
merged 5 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions src/Java.Interop/Java.Interop/JavaException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public unsafe JavaException ()
var peer = JniPeerMembers.InstanceMethods.StartCreateInstance ("()V", GetType (), null);
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null);
JavaStackTrace = GetJavaStack (PeerReference);
SetJavaStackTrace ();
}

public unsafe JavaException (string message)
Expand All @@ -55,7 +55,7 @@ public unsafe JavaException (string message)
} finally {
JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose);
}
JavaStackTrace = GetJavaStack (PeerReference);
SetJavaStackTrace ();
}

public unsafe JavaException (string message, Exception innerException)
Expand All @@ -72,15 +72,22 @@ public unsafe JavaException (string message, Exception innerException)
} finally {
JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose);
}
JavaStackTrace = GetJavaStack (PeerReference);
SetJavaStackTrace ();
}

protected JavaException (ref JniObjectReference reference, JniObjectReferenceOptions transfer, JniObjectReference throwableOverride)
: base (GetMessage (throwableOverride), GetCause (throwableOverride))
{
Construct (ref reference, transfer);
SetJavaStackTrace (throwableOverride);
}

public JavaException (ref JniObjectReference reference, JniObjectReferenceOptions transfer)
: base (GetMessage (ref reference, transfer), GetCause (ref reference, transfer))
{
Construct (ref reference, transfer);
if (PeerReference.IsValid)
JavaStackTrace = GetJavaStack (PeerReference);
SetJavaStackTrace ();
}

protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options)
Expand Down Expand Up @@ -183,6 +190,13 @@ public override unsafe int GetHashCode ()
{
if (transfer == JniObjectReferenceOptions.None)
return null;
return GetMessage (reference);
}

static string? GetMessage (JniObjectReference reference)
{
if (!reference.IsValid)
return null;

var m = _members.InstanceMethods.GetMethodInfo ("getMessage.()Ljava/lang/String;");
var s = JniEnvironment.InstanceMethods.CallObjectMethod (reference, m);
Expand All @@ -193,12 +207,30 @@ public override unsafe int GetHashCode ()
{
if (transfer == JniObjectReferenceOptions.None)
return null;
return GetCause (reference);
}

static Exception? GetCause (JniObjectReference reference)
{
if (!reference.IsValid)
return null;

var m = _members.InstanceMethods.GetMethodInfo ("getCause.()Ljava/lang/Throwable;");
var e = JniEnvironment.InstanceMethods.CallObjectMethod (reference, m);
return JniEnvironment.Runtime.GetExceptionForThrowable (ref e, JniObjectReferenceOptions.CopyAndDispose);
}

protected void SetJavaStackTrace (JniObjectReference peerReferenceOverride = default)
{
if (!peerReferenceOverride.IsValid) {
peerReferenceOverride = PeerReference;
}
if (!peerReferenceOverride.IsValid) {
return;
}
JavaStackTrace = GetJavaStack (peerReferenceOverride);
}

unsafe string? GetJavaStack (JniObjectReference handle)
{
using (var StringWriter_class = new JniType ("java/io/StringWriter"))
Expand Down
24 changes: 15 additions & 9 deletions src/Java.Interop/Java.Interop/JavaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,35 @@

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;

namespace Java.Interop
{
[JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)]
[Serializable]
unsafe public class JavaObject : IJavaPeerable
{
internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;

readonly static JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (JavaObject));

public int JniIdentityHashCode { get; private set; }
public JniManagedPeerStates JniManagedPeerState { get; private set; }
[NonSerialized] int identityHashCode;
[NonSerialized] JniManagedPeerStates managedPeerState;

public int JniIdentityHashCode => identityHashCode;

public JniManagedPeerStates JniManagedPeerState => managedPeerState;

#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
JniObjectReference reference;
[NonSerialized] JniObjectReference reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
IntPtr handle;
JniObjectReferenceType handle_type;
[NonSerialized] IntPtr handle;
[NonSerialized] JniObjectReferenceType handle_type;
#pragma warning disable 0169
// Used by JavaInteropGCBridge
IntPtr weak_handle;
int refs_added;
[NonSerialized] IntPtr weak_handle;
[NonSerialized] int refs_added;
#pragma warning restore 0169
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS

Expand Down Expand Up @@ -151,12 +157,12 @@ void IJavaPeerable.Finalized ()

void IJavaPeerable.SetJniIdentityHashCode (int value)
{
JniIdentityHashCode = value;
identityHashCode = value;
}

void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
{
JniManagedPeerState = value;
managedPeerState = value;
}

void IJavaPeerable.SetPeerReference (JniObjectReference reference)
Expand Down
9 changes: 7 additions & 2 deletions src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,13 @@ public void ConstructPeer (IJavaPeerable peer, ref JniObjectReference reference,

var newRef = peer.PeerReference;
if (newRef.IsValid) {
// Activation! See ManagedPeer.RunConstructor
peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Activatable);
JniObjectReference.Dispose (ref reference, options);

// Activation? See ManagedPeer.Construct, CreatePeer
// Instance was already added, don't add again
if (peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Activatable)) {
return;
}
JniObjectReference.Dispose (ref reference, options);
newRef = newRef.NewGlobalRef ();
} else if (options == JniObjectReferenceOptions.None) {
Expand Down
2 changes: 2 additions & 0 deletions src/Java.Interop/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ static Java.Interop.JniEnvironment.BeginMarshalMethod(nint jnienv, out Java.Inte
static Java.Interop.JniEnvironment.EndMarshalMethod(ref Java.Interop.JniTransition transition) -> void
virtual Java.Interop.JniRuntime.OnEnterMarshalMethod() -> void
virtual Java.Interop.JniRuntime.OnUserUnhandledException(ref Java.Interop.JniTransition transition, System.Exception! e) -> void
Java.Interop.JavaException.JavaException(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, Java.Interop.JniObjectReference throwableOverride) -> void
Java.Interop.JavaException.SetJavaStackTrace(Java.Interop.JniObjectReference peerReferenceOverride = default(Java.Interop.JniObjectReference)) -> void
Java.Interop.JniTypeSignatureAttribute.InvokerType.get -> System.Type?
Java.Interop.JniTypeSignatureAttribute.InvokerType.set -> void