From 6378cc6ad49935fc23fadf585b68572d4fe540f4 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 26 Feb 2025 08:12:04 -0500 Subject: [PATCH 1/3] [Hello-Java.Base] Add support for Java Callable Wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Hello-Java.Base to use Java.Interop.Sdk, so that it (kinda, sorta) "automagically" gets support for generating Java Callable Wrappers as part of its build. Add a custom `Java.Lang.Object` subclass and use it. …which in turn requires creating a new `JreTypeManager` subclass to provide the typemap information, because "Java.Interop.Sdk" is not fleshed out enough to provide that information itself. --- .../Hello-Java.Base/Hello-Java.Base.csproj | 10 ++++ samples/Hello-Java.Base/Program.cs | 50 ++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/samples/Hello-Java.Base/Hello-Java.Base.csproj b/samples/Hello-Java.Base/Hello-Java.Base.csproj index e2d023c86..1405024ff 100644 --- a/samples/Hello-Java.Base/Hello-Java.Base.csproj +++ b/samples/Hello-Java.Base/Hello-Java.Base.csproj @@ -7,6 +7,14 @@ enable Hello.App + + + + + + + $(MSBuildThisFileDirectory)bin\$(Configuration)\ + @@ -15,4 +23,6 @@ + + diff --git a/samples/Hello-Java.Base/Program.cs b/samples/Hello-Java.Base/Program.cs index b1e0d5bac..213a7e7f1 100644 --- a/samples/Hello-Java.Base/Program.cs +++ b/samples/Hello-Java.Base/Program.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.IO; using System.Threading; using Mono.Options; @@ -26,7 +29,7 @@ public static void Main (string[] args) $"{{PATH}} to JVM to use. Default is:\n {jvmPath}", v => jvmPath = v }, { "m", - "Create multiple Java VMs. This will likely creash.", + "Create multiple Java VMs. This will likely crash.", v => createMultipleVMs = v != null }, { "t", $"Timing; invoke Object.hashCode() {N} times, print average.", @@ -43,6 +46,12 @@ public static void Main (string[] args) var builder = new JreRuntimeOptions () { JniAddNativeMethodRegistrationAttributePresent = true, JvmLibraryPath = jvmPath, + ClassPath = { + Path.Combine (Path.GetDirectoryName (typeof (App).Assembly.Location)!, "Hello-Java.Base.jar"), + }, + TypeManager = new HelloTypeManager (new () { + [MyJLO.JniTypeName] = typeof (MyJLO), + }), }; builder.AddOption ("-Xcheck:jni"); @@ -63,7 +72,7 @@ public static void Main (string[] args) static void CreateJLO () { - var jlo = new Java.Lang.Object (); + var jlo = new MyJLO (); Console.WriteLine ($"binding? {jlo.ToString ()}"); } @@ -115,4 +124,41 @@ static unsafe void CreateAnotherJVM () } } } + public class HelloTypeManager : JreTypeManager + { + + Dictionary typeMappings; + + public HelloTypeManager (Dictionary typeMappings) + { + this.typeMappings = typeMappings; + } + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) + yield return t; + if (typeMappings.TryGetValue (jniSimpleReference, out var target)) + yield return target; + } + + protected override IEnumerable GetSimpleReferences (Type type) + { + return base.GetSimpleReferences (type) + .Concat (CreateSimpleReferencesEnumerator (type)); + } + + IEnumerable CreateSimpleReferencesEnumerator (Type type) + { + foreach (var e in typeMappings) { + if (e.Value == type) + yield return e.Key; + } + } + } + + [JniTypeSignature (JniTypeName)] + class MyJLO : Java.Lang.Object { + internal const string JniTypeName = "net/dot/jni/sample/MyJLO"; + } } From c8826d72dcf65af2ad212c0f29b9042a88bba195 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 26 Feb 2025 09:25:20 -0500 Subject: [PATCH 2/3] Fix the build break. --- build-tools/Java.Interop.Sdk/Sdk/Sdk.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets b/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets index 92ef90e2a..466fb605d 100644 --- a/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets +++ b/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets @@ -64,6 +64,7 @@ @@ -105,6 +106,7 @@ @@ -120,6 +122,7 @@ From 915546711d5b481cd8c5fb44d9cf76d9cab6fa84 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 26 Feb 2025 09:42:04 -0500 Subject: [PATCH 3/3] Simplify Move `GetTypesForSimpleReference()`/etc. into `JreTypeManager`, add `JreRuntimeOptions.TypeMappings` to make it easier to provide type mappings without needing to subclass `JreTypeManager` or otherwise worry about the TypeManager. --- samples/Hello-Java.Base/Program.cs | 36 +------------- .../Java.Interop/JreRuntime.cs | 5 +- .../Java.Interop/JreTypeManager.cs | 38 ++++++++++++++ tests/TestJVM/TestJVM.cs | 49 +++---------------- 4 files changed, 52 insertions(+), 76 deletions(-) diff --git a/samples/Hello-Java.Base/Program.cs b/samples/Hello-Java.Base/Program.cs index 213a7e7f1..733590374 100644 --- a/samples/Hello-Java.Base/Program.cs +++ b/samples/Hello-Java.Base/Program.cs @@ -49,9 +49,9 @@ public static void Main (string[] args) ClassPath = { Path.Combine (Path.GetDirectoryName (typeof (App).Assembly.Location)!, "Hello-Java.Base.jar"), }, - TypeManager = new HelloTypeManager (new () { + TypeMappings = { [MyJLO.JniTypeName] = typeof (MyJLO), - }), + }, }; builder.AddOption ("-Xcheck:jni"); @@ -124,38 +124,6 @@ static unsafe void CreateAnotherJVM () } } } - public class HelloTypeManager : JreTypeManager - { - - Dictionary typeMappings; - - public HelloTypeManager (Dictionary typeMappings) - { - this.typeMappings = typeMappings; - } - - protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) - { - foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) - yield return t; - if (typeMappings.TryGetValue (jniSimpleReference, out var target)) - yield return target; - } - - protected override IEnumerable GetSimpleReferences (Type type) - { - return base.GetSimpleReferences (type) - .Concat (CreateSimpleReferencesEnumerator (type)); - } - - IEnumerable CreateSimpleReferencesEnumerator (Type type) - { - foreach (var e in typeMappings) { - if (e.Value == type) - yield return e.Key; - } - } - } [JniTypeSignature (JniTypeName)] class MyJLO : Java.Lang.Object { diff --git a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs index 811523b35..8da7d8909 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs @@ -35,6 +35,9 @@ public class JreRuntimeOptions : JniRuntime.CreationOptions { public TextWriter? JniGlobalReferenceLogWriter {get; set;} public TextWriter? JniLocalReferenceLogWriter {get; set;} + internal Dictionary? typeMappings; + public IDictionary TypeMappings => typeMappings ??= new (); + internal JvmLibraryHandler? LibraryHandler {get; set;} public JreRuntimeOptions () @@ -85,7 +88,7 @@ static unsafe JreRuntimeOptions CreateJreVM (JreRuntimeOptions builder) builder.LibraryHandler = JvmLibraryHandler.Create (); #if NET - builder.TypeManager ??= new JreTypeManager (); + builder.TypeManager ??= new JreTypeManager (builder.typeMappings); #endif // NET bool onMono = Type.GetType ("Mono.Runtime", throwOnError: false) != null; diff --git a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs index 061b4e7ad..7be7bbee9 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs @@ -18,6 +18,44 @@ namespace Java.Interop { public class JreTypeManager : JniRuntime.JniTypeManager { + IDictionary? typeMappings; + + public JreTypeManager () + : this (null) + { + } + + public JreTypeManager (IDictionary? typeMappings) + { + this.typeMappings = typeMappings; + } + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) + yield return t; + if (typeMappings == null) + yield break; + if (typeMappings.TryGetValue (jniSimpleReference, out var target)) + yield return target; + } + + protected override IEnumerable GetSimpleReferences (Type type) + { + return base.GetSimpleReferences (type) + .Concat (CreateSimpleReferencesEnumerator (type)); + } + + IEnumerable CreateSimpleReferencesEnumerator (Type type) + { + if (typeMappings == null) + yield break; + foreach (var e in typeMappings) { + if (e.Value == type) + yield return e.Key; + } + } + const string NotUsedInAndroid = "This code path is not used in Android projects."; public override void RegisterNativeMembers ( diff --git a/tests/TestJVM/TestJVM.cs b/tests/TestJVM/TestJVM.cs index caf00ad44..0272b7142 100644 --- a/tests/TestJVM/TestJVM.cs +++ b/tests/TestJVM/TestJVM.cs @@ -23,7 +23,6 @@ public TestJVMOptions (Assembly? callingAssembly = null) public ICollection JarFilePaths {get;} = new List (); public Assembly CallingAssembly {get; set;} - public Dictionary? TypeMappings {get; set;} internal JdkInfo? JdkInfo {get; set;} } @@ -141,9 +140,13 @@ public TestJVM (string[]? jars = null, Dictionary? typeMappings = static TestJVMOptions CreateOptions (string[]? jarFiles, Assembly callingAssembly, Dictionary? typeMappings) { var o = new TestJVMOptions { - TypeMappings = typeMappings, CallingAssembly = callingAssembly, }; + if (typeMappings != null) { + foreach (var e in typeMappings) { + o.TypeMappings.Add (e.Key, e.Value); + } + } if (jarFiles != null) { foreach (var jar in jarFiles) { o.JarFilePaths.Add (jar); @@ -153,48 +156,12 @@ static TestJVMOptions CreateOptions (string[]? jarFiles, Assembly callingAssembl } } - public class TestJvmTypeManager : -#if NET - JreTypeManager -#else // !NET - JniRuntime.JniTypeManager -#endif // !NET + public class TestJvmTypeManager : JreTypeManager { - Dictionary? typeMappings; - - public TestJvmTypeManager (Dictionary? typeMappings) + public TestJvmTypeManager (IDictionary? typeMappings) + : base (typeMappings) { - this.typeMappings = typeMappings; - } - - protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) - { - foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) - yield return t; - if (typeMappings == null) - yield break; - Type target; -#pragma warning disable CS8600 // huh? - if (typeMappings.TryGetValue (jniSimpleReference, out target)) - yield return target; -#pragma warning restore CS8600 - } - - protected override IEnumerable GetSimpleReferences (Type type) - { - return base.GetSimpleReferences (type) - .Concat (CreateSimpleReferencesEnumerator (type)); - } - - IEnumerable CreateSimpleReferencesEnumerator (Type type) - { - if (typeMappings == null) - yield break; - foreach (var e in typeMappings) { - if (e.Value == type) - yield return e.Key; - } } } }