diff --git a/src/Java.Interop/Java.Interop/JavaException.cs b/src/Java.Interop/Java.Interop/JavaException.cs index 0bfa3fd58..b07735b5a 100644 --- a/src/Java.Interop/Java.Interop/JavaException.cs +++ b/src/Java.Interop/Java.Interop/JavaException.cs @@ -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) @@ -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) @@ -72,7 +72,14 @@ 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) @@ -80,7 +87,7 @@ public JavaException (ref JniObjectReference reference, JniObjectReferenceOption { Construct (ref reference, transfer); if (PeerReference.IsValid) - JavaStackTrace = GetJavaStack (PeerReference); + SetJavaStackTrace (); } protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options) @@ -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); @@ -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")) diff --git a/src/Java.Interop/Java.Interop/JavaObject.cs b/src/Java.Interop/Java.Interop/JavaObject.cs index 22e382fba..02a69e061 100644 --- a/src/Java.Interop/Java.Interop/JavaObject.cs +++ b/src/Java.Interop/Java.Interop/JavaObject.cs @@ -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 @@ -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) diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs index 207359e61..55af4f7b4 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -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) { diff --git a/src/Java.Interop/PublicAPI.Unshipped.txt b/src/Java.Interop/PublicAPI.Unshipped.txt index e0f851bb0..d4be03231 100644 --- a/src/Java.Interop/PublicAPI.Unshipped.txt +++ b/src/Java.Interop/PublicAPI.Unshipped.txt @@ -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