diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs index 95b907ea4..03ac65994 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -86,6 +86,8 @@ protected virtual void Dispose (bool disposing) public abstract List GetSurfacedPeers (); + public abstract void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object? []? argumentValues); + public void ConstructPeer (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options) { if (peer == null) diff --git a/src/Java.Interop/Java.Interop/ManagedPeer.cs b/src/Java.Interop/Java.Interop/ManagedPeer.cs index 121e11c87..2b720d41a 100644 --- a/src/Java.Interop/Java.Interop/ManagedPeer.cs +++ b/src/Java.Interop/Java.Interop/ManagedPeer.cs @@ -93,31 +93,17 @@ static void Construct ( var ptypes = GetParameterTypes (JniEnvironment.Strings.ToString (n_constructorSignature)); var pvalues = GetValues (runtime, new JniObjectReference (n_constructorArguments), ptypes); - var ctor = type.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .FirstOrDefault (c => - c.GetParameters ().Select (p => p.ParameterType).SequenceEqual (ptypes)); - if (ctor == null) { + var cinfo = type.GetConstructor (ptypes); + if (cinfo == null) { throw CreateMissingConstructorException (type, ptypes); } + if (self != null) { - ctor.Invoke (self, pvalues); + cinfo.Invoke (self, pvalues); return; } - try { - var f = JniEnvironment.Runtime.MarshalMemberBuilder.CreateConstructActivationPeerFunc (ctor); - f (ctor, new JniObjectReference (n_self), pvalues); - } - catch (Exception e) { - var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", - r_self, - runtime.ValueManager.GetJniIdentityHashCode (r_self).ToString ("x"), - JniEnvironment.Types.GetJniTypeNameFromInstance (r_self), - type.FullName); - Debug.WriteLine (m); - - throw new NotSupportedException (m, e); - } + JniEnvironment.Runtime.ValueManager.ActivatePeer (self, new JniObjectReference (n_self), cinfo, pvalues); } catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { envp.SetPendingException (e); @@ -127,29 +113,33 @@ static void Construct ( } } - static Exception CreateJniLocationException () - { - using (var e = new JavaException ()) { - return new JniLocationException (e.ToString ()); - } - } - - static Exception CreateMissingConstructorException (Type type, Type[] ptypes) + static Exception CreateMissingConstructorException (Type type, Type [] ptypes) { var message = new StringBuilder (); message.Append ("Unable to find constructor "); message.Append (type.FullName); message.Append ("("); + if (ptypes.Length > 0) { message.Append (ptypes [0].FullName); for (int i = 1; i < ptypes.Length; ++i) message.Append (", ").Append (ptypes [i].FullName); } + message.Append (")"); message.Append (". Please provide the missing constructor."); + return new NotSupportedException (message.ToString (), CreateJniLocationException ()); } + + static Exception CreateJniLocationException () + { + using (var e = new JavaException ()) { + return new JniLocationException (e.ToString ()); + } + } + static Type[] GetParameterTypes (string? signature) { if (string.IsNullOrEmpty (signature)) diff --git a/src/Java.Interop/Properties/AssemblyInfo.cs b/src/Java.Interop/Properties/AssemblyInfo.cs index 7b392dd50..b599f355d 100644 --- a/src/Java.Interop/Properties/AssemblyInfo.cs +++ b/src/Java.Interop/Properties/AssemblyInfo.cs @@ -28,3 +28,10 @@ "814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0" + "d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b" + "2c9733db")] +[assembly: InternalsVisibleTo ( + "Java.Runtime.Environment, PublicKey=" + + "0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf1" + + "6cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2" + + "814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0" + + "d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b" + + "2c9733db")] diff --git a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs index b64864a29..989bf98a6 100644 --- a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs @@ -1,7 +1,11 @@ -using System; +using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace Java.Interop { @@ -229,6 +233,32 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference) return null; } + static Exception CreateJniLocationException () + { + using (var e = new JavaException ()) { + return new JniLocationException (e.ToString ()); + } + } + + public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues) + { + var runtime = JniEnvironment.Runtime; + + try { + var f = runtime.MarshalMemberBuilder.CreateConstructActivationPeerFunc (cinfo); + f (cinfo, reference, argumentValues); + } catch (Exception e) { + var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", + reference, + runtime.ValueManager.GetJniIdentityHashCode (reference).ToString ("x"), + JniEnvironment.Types.GetJniTypeNameFromInstance (reference), + cinfo.DeclaringType.FullName); + Debug.WriteLine (m); + + throw new NotSupportedException (m, e); + } + } + public override void FinalizePeer (IJavaPeerable value) { var h = value.PeerReference; diff --git a/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs b/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs index 2e865c225..f8f8c42bb 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Reflection; using System.Collections.Generic; using Java.Interop; @@ -59,6 +60,11 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference) { return null; } + + public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues) + { + throw new NotImplementedException (); + } } [Test] diff --git a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs index b7f81102e..5503dcbf6 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using System.Collections.Generic; using System.Threading; @@ -151,6 +152,11 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference) return null; } + public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues) + { + throw new NotImplementedException (); + } + public override void RemovePeer (IJavaPeerable peer) { }