From 1adb7964a2033c83c298c070f2d1ab896d92671b Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 26 Oct 2023 14:08:04 -0400 Subject: [PATCH] [generator] `generator --lang-features=emit-legacy-interface-invokers` (#1145) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/xamarin/java.interop/issues/910 Context: bc5bcf4f0ef07aab898f2643d2a25f66512d98ed Context: https://github.com/xamarin/java.interop/issues/858 Consider the Java `java.lang.Runnable` interface: package java.lang; public interface Runnable { void run (); } This is bound as: package Java.Lang; public interface IRunnable : IJavaPeerable { void Run (); } with some slight differences depending on whether we're dealing with .NET Android (`generator --codegen-target=xajavainterop1`) or `src/Java.Base` (`generator --codegen-target=javainterop1`). Now, assume a Java API + corresponding binding which returns a `Runnable` instance: package example; public class Whatever { public static Runnable createRunnable(); } You can invoke `IRunnable.Run()` on the return value: IRunnable r = Whatever.CreateRunnable(); r.Run(); but how does that work? This works via an "interface Invoker", which is a class emitted by `generator` which implements the interface and invokes the interface methods through JNI: internal partial class IRunnableInvoker : Java.Lang.Object, IRunnable { public void Run() => … } Once Upon A Time™, the interface invoker implementation mirrored that of classes: a static `IntPtr` field held the `jmethodID` value, which would be looked up on first-use and cached for subsequent invocations: partial class IRunnableInvoker { static IntPtr id_run; public unsafe void Run() { if (id_run == IntPtr.Zero) id_run = JNIEnv.GetMethodID (class_ref, "run", "()V"); JNIEnv.CallVoidMethod (Handle, id_run, …); } } This approach works until you have interface inheritance and methods which come from inherited interfaces: package android.view; public /* partial */ interface ViewManager { void addView(View view, ViewGroup.LayoutParams params); } public /* partial */ interface WindowManager extends ViewManager { void removeViewImmediate(View view); } This would be bound as: namespace Android.Views; public partial interface IViewManager : IJavaPeerable { void AddView (View view, ViewGroup.LayoutParams @params); } public partial IWindowManager : IViewManager { void RemoveViewImmediate (View view); } internal partial class IWindowManagerInvoker : Java.Lang.Object, IWindowManager { static IntPtr id_addView; public void AddView(View view, ViewGroup.LayoutParams @params) { if (id_addView == IntPtr.Zero) id_run = JNIEnv.GetMethodID (class_ref, "addView", "…"); JNIEnv.CallVoidMethod (Handle, id_addView, …); } } Unfortunately, *invoking* `IViewManager.AddView()` through an `IWindowManagerInvoker` would crash! D/dalvikvm( 6645): GetMethodID: method not found: Landroid/view/WindowManager;.addView:(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V I/MonoDroid( 6645): UNHANDLED EXCEPTION: Java.Lang.NoSuchMethodError: Exception of type 'Java.Lang.NoSuchMethodError' was thrown. I/MonoDroid( 6645): at Android.Runtime.JNIEnv.GetMethodID (intptr,string,string) I/MonoDroid( 6645): at Android.Views.IWindowManagerInvoker.AddView (Android.Views.View,Android.Views.ViewGroup/LayoutParams) I/MonoDroid( 6645): at Mono.Samples.Hello.HelloActivity.OnCreate (Android.OS.Bundle) I/MonoDroid( 6645): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) I/MonoDroid( 6645): at (wrapper dynamic-method) object.ecadbe0b-9124-445e-a498-f351075f6c89 (intptr,intptr,intptr) Interfaces are not classes, and this is one of the places that this is most apparent. Because of this crash, we had to use *instance* `jmethodID` caches: internal partial class IWindowManagerInvoker : Java.Lang.Object, IWindowManager { IntPtr id_addView; public void AddView(View view, ViewGroup.LayoutParams @params) { if (id_addView == IntPtr.Zero) id_run = JNIEnv.GetMethodID (class_ref, "addView", "…"); JNIEnv.CallVoidMethod (Handle, id_addView, …); } } Pro: no more crash! Con: *every different instance* of `IWindowManagerInvoker` needs to separately lookup whatever methods are invoked. There is *some* caching, so repeated calls to `AddView()` on the same instance will hit the cache, but if you obtain a different `IWindowManager` instance, `jmethodID` values will need to be looked up again. This was "fine", until xamarin/java.interop#858 enters the picture: interface invokers were full of Android-isms -- `Android.Runtime.JNIEnv.GetMethodID()`! `JNIEnv.CallVoidMethod()`! -- and thus ***not*** APIs that @jonpryor wished to expose within desktop Java.Base bindings. Enter `generator --lang-features=emit-legacy-interface-invokers`: when *not* specified, interface invokers will now use `JniPeerMembers` for method lookup and invocation, allowing `jmethodID` values to be cached *across* instances. In order to prevent the runtime crash, an interface may have *multiple* `JniPeerMembers` values, one per implemented interface, which is used to invoke methods from that interface. `IWindowManagerInvoker` now becomes: internal partial class IWindowManagerInvoker : Java.Lang.Object, IWindowManager { static readonly JniPeerMembers _members_android_view_ViewManager = …; static readonly JniPeerMembers _members_android_view_WindowManager = …; public void AddView(View view, ViewGroup.LayoutParams @params) { const string __id = "addView.…"; _members_android_view_ViewManager.InstanceMethods.InvokeAbstractVoidMethod (__id, this, …); } public void RemoveViewImmediate(View view) { const string __id = "removeViewImmediate.…"; _members_android_view_WindowManager.InstanceMethods.InvokeAbstractVoidMethod (__id, this, …); } } This has two advantages: 1. More caching! 2. Desktop `Java.Base` binding can now have interface invokers. Update `tests/generator-Tests` expected output. Note: to keep this patch smaller, JavaInterop1 output uses the new pattern, and only *some* XAJavaInterop1 tests use the new pattern. Added [CS0114][0] to `$(NoWarn)` in `Java.Base.csproj` to ignore warnings such as: …/src/Java.Base/obj/Debug-net7.0/mcw/Java.Lang.ICharSequence.cs(195,25): warning CS0114: 'ICharSequenceInvoker.ToString()' hides inherited member 'Object.ToString()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. [Ignoring CS0114 is also done in `Mono.Android.dll` as well][1], so this is not a new or unique requirement. Update `Java.Interop.dll` so that `JniRuntime.JniValueManager.GetActivationConstructor()` now knows about and looks for `*Invoker` types, then uses the activation constructor from the `*Invoker` type when the source type is an abstract `class` or `interface`. Update `tests/Java.Base-Tests` to test for implicit `*Invoker` lookup and invocation support. ~~ Property Setters ~~ While testing on xamarin/xamarin-android#8339, we hit this error (among others, to be addressed later): src/Mono.Android/obj/Debug/net8.0/android-34/mcw/Android.Views.IWindowInsetsController.cs(304,41): error CS0103: The name 'behavior' does not exist in the current context This was caused because of code such as: public partial interface IWindowInsetsController { public unsafe int SystemBarsBehavior { get { const string __id = "getSystemBarsBehavior.()I"; try { var __rm = _members_IWindowInsetsController.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); return __rm; } finally { } } set { const string __id = "setSystemBarsBehavior.(I)V"; try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; __args [0] = new JniArgumentValue (behavior); _members_IWindowInsetsController.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); } finally { } } } } This happened because when emitting the property setter, we need to update the `set*` method's parameter name to be `value` so that the normal property setter body is emitted properly. Update `InterfaceInvokerProperty.cs` so that the parameter name is set to `value`. ~~ Performance ~~ What does this do for performance? Add a new `InterfaceInvokerTiming` test fixture to `Java.Interop-PerformanceTests.dll`, which: 1. "Reimplements" the "legacy" and "JniPeerMembers" Invoker strategies 2. For each Invoker strategy: a. Invokes a Java method which returns a `java.lang.Runnable` instance b. Invokes `Runnable.run()` on the instance returned by (2.a) …100 times. c. Repeat (2.a) and (2.b) 100 times. The result is that using `JniPeerMembers` is *much* faster: % dotnet build tests/Java.Interop-PerformanceTests/*.csproj && \ dotnet test --logger "console;verbosity=detailed" bin/TestDebug-net7.0/Java.Interop-PerformanceTests.dll --filter "Name~InterfaceInvokerTiming" … Passed InterfaceInvokers [1 s] Standard Output Messages: ## InterfaceInvokers Timing: instanceIds: 00:00:01.1095502 ## InterfaceInvokers Timing: peerMembers: 00:00:00.1400427 Using `JniPeerMembers` takes ~1/8th the time as using `jmethodID`s. TODO: something is *probably* wrong with my test -- reviews welcome! -- as when I increase the (2.b) iteration count, the `peerMembers` time is largely unchanged (~0.14s), while the `instanceIds` time increases linearly. *Something* is wrong there. I'm not sure what. (Or *nothing* is wrong, and instance `jmethodID` are just *that* bad.) [0]: https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0114 [1]: https://github.com/xamarin/xamarin-android/blob/d5c4ec09f7658428a10bbe49c8a7a3eb2f71cb86/src/Mono.Android/Mono.Android.csproj#L12C7-L12C7 --- .../automation/templates/core-tests.yaml | 2 +- src/Java.Base/Java.Base.csproj | 2 +- src/Java.Base/Java.Lang/ICharSequence.cs | 5 + src/Java.Base/Transforms/Metadata.xml | 12 +- .../JniRuntime.JniValueManager.cs | 31 ++++- .../Java.Base/JavaToManagedTests.cs | 36 +++++ .../microsoft/java_base_tests/Invoker.java | 13 +- .../Java.Interop/JavaTiming.cs | 5 + .../Java.Interop/TimingTests.cs | 90 +++++++++++++ .../interop/performance/JavaTiming.java | 9 ++ .../Integration-Tests/BaseGeneratorTest.cs | 1 + .../Integration-Tests/Interfaces.cs | 9 +- .../SupportFiles/Java_Lang_ICharSequence.cs | 12 +- .../SupportFiles/Java_Lang_String.cs | 13 +- .../WriteDuplicateInterfaceEventArgs.txt | 41 ++++++ .../JavaInterop1/WriteInterface.txt | 111 +++++++++++++++ .../Unit-Tests/CodeGeneratorTestBase.cs | 1 + .../Xamarin.Test.IExtendedInterface.cs | 36 +++++ .../Xamarin.Test.PublicClass.cs | 25 ++++ .../Xamarin.Test.II1.cs | 25 ++++ .../Xamarin.Test.II2.cs | 25 ++++ .../TestInterface/ClassWithoutNamespace.cs | 76 +++++++++++ .../IInterfaceWithoutNamespace.cs | 37 +++++ .../TestInterface/Java.Lang.Object.cs | 10 ++ .../TestInterface/Java.Lang.String.cs | 10 ++ .../TestInterface/Java.Util.ICollection.cs | 59 ++++++++ .../TestInterface/Java.Util.IDeque.cs | 59 ++++++++ .../TestInterface/Java.Util.IQueue.cs | 57 ++++++++ .../TestInterface/Mono.Android.projitems | 3 + .../Test.ME.GenericImplementation.cs | 19 ++- ....ME.GenericObjectPropertyImplementation.cs | 10 ++ .../Test.ME.GenericStringImplementation.cs | 19 ++- ....ME.GenericStringPropertyImplementation.cs | 16 ++- .../Test.ME.IGenericInterface.cs | 30 +++++ .../Test.ME.IGenericPropertyInterface.cs | 40 ++++++ .../TestInterface/Test.ME.ITestInterface.cs | 90 ++++++++----- .../Test.ME.TestInterfaceImplementation.cs | 25 ++-- .../TestInterface/TestInterface.xml | 41 +++++- .../Xamarin.Test.IExtendedInterface.cs | 55 +++----- .../Xamarin.Test.PublicClass.cs | 46 ++----- .../Adapters/Xamarin.Test.IAdapter.cs | 37 +---- .../Adapters/Xamarin.Test.ISpinnerAdapter.cs | 37 +---- .../Core_Jar2Xml/Android.Text.ISpannable.cs | 53 +++----- .../Core_Jar2Xml/Android.Text.ISpanned.cs | 53 +++----- .../Core_Jar2Xml/Android.Views.View.cs | 51 ++----- ...e.Android.Exoplayer.Drm.IExoMediaCrypto.cs | 54 +++----- ...ogle.Android.Exoplayer.Drm.IExoMediaDrm.cs | 126 ++++++------------ .../Xamarin.Test.II1.cs | 46 ++----- .../Xamarin.Test.II2.cs | 46 ++----- .../Xamarin.Test.NotificationCompatBase.cs | 51 ++----- .../IInterfaceWithoutNamespace.cs | 46 ++----- .../TestInterface/Java.Util.ICollection.cs | 111 +++++++++++++++ .../TestInterface/Java.Util.IDeque.cs | 111 +++++++++++++++ .../TestInterface/Java.Util.IQueue.cs | 109 +++++++++++++++ .../TestInterface/Mono.Android.projitems | 3 + ....ME.GenericObjectPropertyImplementation.cs | 6 +- ....ME.GenericStringPropertyImplementation.cs | 6 +- .../Test.ME.IGenericInterface.cs | 53 +++----- .../Test.ME.IGenericPropertyInterface.cs | 69 ++++------ .../TestInterface/Test.ME.ITestInterface.cs | 87 +++++------- .../TestInterface/__NamespaceMapping__.cs | 2 + .../java.lang.Enum/Java.Lang.IComparable.cs | 55 +++----- tools/generator/CodeGenerationOptions.cs | 1 + tools/generator/CodeGenerator.cs | 1 + tools/generator/CodeGeneratorOptions.cs | 4 +- .../ClassGen.cs | 2 +- .../GenBase.cs | 21 +++ .../InterfaceGen.cs | 2 +- .../ReturnValue.cs | 2 +- .../Symbols/CharSequenceSymbol.cs | 2 +- .../generator/SourceWriters/BoundInterface.cs | 5 +- .../generator/SourceWriters/ClassInvokers.cs | 16 +-- .../Extensions/SourceWriterExtensions.cs | 14 +- ...ExplicitInterfaceImplementationProperty.cs | 35 ++++- .../SourceWriters/InterfaceInvokerClass.cs | 66 ++++++--- .../SourceWriters/InterfaceInvokerMethod.cs | 25 +++- .../SourceWriters/InterfaceInvokerProperty.cs | 42 ++++-- .../SourceWriters/PeerMembersField.cs | 4 +- 78 files changed, 1835 insertions(+), 825 deletions(-) create mode 100644 tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs create mode 100644 tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs create mode 100644 tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs create mode 100644 tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs create mode 100644 tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs create mode 100644 tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs create mode 100644 tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs create mode 100644 tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs diff --git a/build-tools/automation/templates/core-tests.yaml b/build-tools/automation/templates/core-tests.yaml index 98ad5f841..6d91b1504 100644 --- a/build-tools/automation/templates/core-tests.yaml +++ b/build-tools/automation/templates/core-tests.yaml @@ -132,7 +132,7 @@ steps: inputs: command: test testRunTitle: Java.Interop-Performance ($(DotNetTargetFramework) - ${{ parameters.platformName }}) - arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Interop-PerformanceTests.dll + arguments: --logger "console;verbosity=detailed" bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Interop-PerformanceTests.dll continueOnError: true retryCountOnTaskFailure: 1 diff --git a/src/Java.Base/Java.Base.csproj b/src/Java.Base/Java.Base.csproj index 15a118a6f..b44aea0b6 100644 --- a/src/Java.Base/Java.Base.csproj +++ b/src/Java.Base/Java.Base.csproj @@ -4,7 +4,7 @@ $(DotNetTargetFramework) true enable - $(NoWarn);8764 + $(NoWarn);8764;0114 diff --git a/src/Java.Base/Java.Lang/ICharSequence.cs b/src/Java.Base/Java.Lang/ICharSequence.cs index 678e0e67a..cff227468 100644 --- a/src/Java.Base/Java.Lang/ICharSequence.cs +++ b/src/Java.Base/Java.Lang/ICharSequence.cs @@ -1,5 +1,10 @@ +using System.Collections; + namespace Java.Lang { + partial class ICharSequenceInvoker : IEnumerable { + } + public static partial class ICharSequenceExtensions { public static ICharSequence[]? ToCharSequenceArray (this string?[]? values) diff --git a/src/Java.Base/Transforms/Metadata.xml b/src/Java.Base/Transforms/Metadata.xml index 3c140ca5a..2c1808d8e 100644 --- a/src/Java.Base/Transforms/Metadata.xml +++ b/src/Java.Base/Transforms/Metadata.xml @@ -1,7 +1,10 @@ - - @@ -54,6 +57,9 @@ ]/method[@name='write']" name="explicitInterface">IDataOutput + + + diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs index 8f22e3269..691ef7b51 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -335,14 +335,33 @@ static Type GetPeerType (Type type) static ConstructorInfo? GetActivationConstructor (Type type) { - return - (from c in type.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - let p = c.GetParameters () - where p.Length == 2 && p [0].ParameterType == ByRefJniObjectReference && p [1].ParameterType == typeof (JniObjectReferenceOptions) - select c) - .FirstOrDefault (); + if (type.IsAbstract || type.IsInterface) { + type = GetInvokerType (type) ?? type; + } + foreach (var c in type.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { + var p = c.GetParameters (); + if (p.Length == 2 && p [0].ParameterType == ByRefJniObjectReference && p [1].ParameterType == typeof (JniObjectReferenceOptions)) + return c; + } + return null; } + static Type? GetInvokerType (Type type) + { + const string suffix = "Invoker"; + Type[] arguments = type.GetGenericArguments (); + if (arguments.Length == 0) + return type.Assembly.GetType (type + suffix); + Type definition = type.GetGenericTypeDefinition (); + int bt = definition.FullName!.IndexOf ("`", StringComparison.Ordinal); + if (bt == -1) + throw new NotSupportedException ("Generic type doesn't follow generic type naming convention! " + type.FullName); + Type? suffixDefinition = definition.Assembly.GetType ( + definition.FullName.Substring (0, bt) + suffix + definition.FullName.Substring (bt)); + if (suffixDefinition == null) + return null; + return suffixDefinition.MakeGenericType (arguments); + } public object? CreateValue (ref JniObjectReference reference, JniObjectReferenceOptions options, Type? targetType = null) { diff --git a/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs b/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs index 72608f5e6..f3580b49c 100644 --- a/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs +++ b/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs @@ -18,6 +18,18 @@ public void InterfaceMethod () Assert.IsTrue (invoked); r.Dispose (); } + + [Test] + public void InterfaceInvokerMethod () + { + int value = 0; + using var c = new MyIntConsumer (v => value = v); + using var r = JavaInvoker.CreateRunnable (c); + r?.Run (); + Assert.AreEqual (0, value); + r?.Run (); + Assert.AreEqual (1, value); + } } class JavaInvoker : JavaObject { @@ -31,6 +43,14 @@ public static unsafe void Run (Java.Lang.IRunnable r) args [0] = new JniArgumentValue (r); _members.StaticMethods.InvokeVoidMethod ("run.(Ljava/lang/Runnable;)V", args); } + + public static unsafe Java.Lang.IRunnable? CreateRunnable (Java.Util.Function.IIntConsumer c) + { + JniArgumentValue* args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (c); + var _rm = _members.StaticMethods.InvokeObjectMethod ("createRunnable.(Ljava/util/function/IntConsumer;)Ljava/lang/Runnable;", args); + return Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref _rm, JniObjectReferenceOptions.CopyAndDispose); + } } [JniTypeSignature ("example/MyRunnable")] @@ -48,4 +68,20 @@ public void Run () action (); } } + + [JniTypeSignature ("example/MyIntConsumer")] + class MyIntConsumer : Java.Lang.Object, Java.Util.Function.IIntConsumer { + + Action action; + + public MyIntConsumer (Action action) + { + this.action = action; + } + + public void Accept (int value) + { + action (value); + } + } } diff --git a/tests/Java.Base-Tests/java/com/microsoft/java_base_tests/Invoker.java b/tests/Java.Base-Tests/java/com/microsoft/java_base_tests/Invoker.java index 7cf4cbc73..93f300285 100644 --- a/tests/Java.Base-Tests/java/com/microsoft/java_base_tests/Invoker.java +++ b/tests/Java.Base-Tests/java/com/microsoft/java_base_tests/Invoker.java @@ -1,8 +1,19 @@ package com.microsoft.java_base_tests; -public class Invoker { +import java.util.function.IntConsumer; + +public final class Invoker { public static void run(Runnable r) { r.run(); } + + public static Runnable createRunnable(final IntConsumer consumer) { + return new Runnable() { + int value; + public void run() { + consumer.accept(value++); + } + }; + } } diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs b/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs index 96f940d2e..dbf586885 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs +++ b/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs @@ -276,6 +276,11 @@ public unsafe JniObjectReference Timing_ToString_JniPeerMembers () const string id = toString_name + "." + toString_sig; return _members.InstanceMethods.InvokeVirtualObjectMethod (id, this, null); } + + public static unsafe JniObjectReference CreateRunnable () + { + return _members.StaticMethods.InvokeObjectMethod ("CreateRunnable.()Ljava/lang/Runnable;", null); + } } [JniTypeSignature (JniTypeName)] diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs index f748e29d7..67e4c1255 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs +++ b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs @@ -776,6 +776,41 @@ public void GenericMarshalingOverhead_Int32ArrayArrayArray () total.Stop (); Console.WriteLine ("## {0} Timing: {1}", nameof (GenericMarshalingOverhead_Int32ArrayArrayArray), total.Elapsed); } + + } + + [TestFixture] + public class InterfaceInvokerTiming : Java.InteropTests.JavaVMFixture { + + [Test] + public void InterfaceInvokers () + { + const int JavaTiming_CreateRunnable_Invocations = 100; + const int Runnable_Run_Invocations = 100; + + var instanceIds = Stopwatch.StartNew (); + for (int i = 0; i < JavaTiming_CreateRunnable_Invocations; ++i) { + var c = JavaTiming.CreateRunnable (); + IMyRunnable r = new LegacyRunnableInvoker (ref c, JniObjectReferenceOptions.CopyAndDispose); + for (int j = 0; j < Runnable_Run_Invocations; ++j) { + r.Run (); + } + r.Dispose (); + } + instanceIds.Stop (); + var peerMembers = Stopwatch.StartNew (); + for (int i = 0; i < JavaTiming_CreateRunnable_Invocations; ++i) { + var c = JavaTiming.CreateRunnable (); + IMyRunnable r = new JniPeerMembersRunnableInvoker (ref c, JniObjectReferenceOptions.CopyAndDispose); + for (int j = 0; j < Runnable_Run_Invocations; ++j) { + r.Run (); + } + r.Dispose (); + } + peerMembers.Stop (); + Console.WriteLine ("## {0} Timing: instanceIds: {1}", nameof (InterfaceInvokers), instanceIds.Elapsed); + Console.WriteLine ("## {0} Timing: peerMembers: {1}", nameof (InterfaceInvokers), peerMembers.Elapsed); + } } class ManagedTiming { @@ -893,5 +928,60 @@ public override object GetValue () return null; } } + + interface IMyRunnable : IJavaPeerable { + void Run(); + } + + class LegacyRunnableInvoker : JavaObject, IMyRunnable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Runnable", typeof (LegacyRunnableInvoker)); + JniObjectReference class_ref; + + public LegacyRunnableInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + var r = JniEnvironment.Types.GetObjectClass (PeerReference); + class_ref = r.NewGlobalRef (); + JniObjectReference.Dispose (ref r); + } + + public override JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override void Dispose (bool disposing) + { + JniObjectReference.Dispose (ref class_ref); + base.Dispose (disposing); + } + + JniMethodInfo id_run; + + public unsafe void Run () + { + if (id_run == null) { + id_run = JniEnvironment.InstanceMethods.GetMethodID (class_ref, "run", "()V"); + } + JniEnvironment.InstanceMethods.CallObjectMethod (PeerReference, id_run); + } + } + + class JniPeerMembersRunnableInvoker : JavaObject, IMyRunnable { + public JniPeerMembersRunnableInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members_IRunnable = new JniPeerMembers ("java/lang/Runnable", typeof (JniPeerMembersRunnableInvoker)); + + public unsafe void Run () + { + const string __id = "run.()V"; + try { + _members_IRunnable.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + } } diff --git a/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java b/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java index 3280f73a7..ca45b787d 100644 --- a/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java +++ b/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java @@ -77,5 +77,14 @@ public static void StaticVoidMethod2IArgs (int obj1, int obj2) public static void StaticVoidMethod3IArgs (int obj1, int obj2, int obj3) { } + + public static Runnable CreateRunnable () + { + return new Runnable () { + public void run () + { + } + }; + } } diff --git a/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs b/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs index 55fe623b0..20040a79d 100644 --- a/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs +++ b/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs @@ -143,6 +143,7 @@ protected void Run (CodeGenerationTarget target, string outputPath, string apiDe AdditionalSourceDirectories.Clear (); Options.CodeGenerationTarget = target; + Options.EmitLegacyInterfaceInvokers = false; Options.ApiDescriptionFile = FullPath (apiDescriptionFile); Options.ManagedCallableWrapperSourceOutputDirectory = FullPath (outputPath); diff --git a/tests/generator-Tests/Integration-Tests/Interfaces.cs b/tests/generator-Tests/Integration-Tests/Interfaces.cs index 2e3074bff..82575d755 100644 --- a/tests/generator-Tests/Integration-Tests/Interfaces.cs +++ b/tests/generator-Tests/Integration-Tests/Interfaces.cs @@ -6,7 +6,14 @@ namespace generatortests [TestFixture] public class Interfaces : BaseGeneratorTest { - protected override bool TryJavaInterop1 => false; + public Interfaces () + { + // warning CS0108: 'IDeque.Add(Object)' hides inherited member 'IQueue.Add(Object)'. Use the new keyword if hiding was intended. + // warning CS0108: 'IQueue.Add(Object)' hides inherited member 'ICollection.Add(Object)'. Use the new keyword if hiding was intended. + AllowWarnings = true; + } + + protected override bool TryJavaInterop1 => true; [Test] public void Generated_OK () diff --git a/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs b/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs index f70a64f6a..47634bbb3 100644 --- a/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs +++ b/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs @@ -1,11 +1,13 @@ -#if !JAVA_INTEROP1 - + using System; -using Android.Runtime; +using Java.Interop; namespace Java.Lang { - public partial interface ICharSequence : IJavaObject + public partial interface ICharSequence : IJavaPeerable +#if !JAVA_INTEROP1 + , Android.Runtime.IJavaObject +#endif // !JAVA_INTEROP1 { char CharAt (int index); int Length (); @@ -13,5 +15,3 @@ public partial interface ICharSequence : IJavaObject string ToString (); } } - -#endif // !JAVA_INTEROP1 \ No newline at end of file diff --git a/tests/generator-Tests/SupportFiles/Java_Lang_String.cs b/tests/generator-Tests/SupportFiles/Java_Lang_String.cs index 69aa1d956..91fbca7d4 100644 --- a/tests/generator-Tests/SupportFiles/Java_Lang_String.cs +++ b/tests/generator-Tests/SupportFiles/Java_Lang_String.cs @@ -1,14 +1,15 @@ -#if !JAVA_INTEROP1 - -using System; +using System; using System.Collections; using System.Collections.Generic; namespace Java.Lang { - public sealed partial class String : global::Java.Lang.Object, Java.Lang.ICharSequence + public sealed partial class String : global::Java.Lang.Object, Java.Lang.ICharSequence, IEnumerable { - public String (string value) + public unsafe String (string value) +#if JAVA_INTEROP1 + : base (ref *InvalidJniObjectReference, Java.Interop.JniObjectReferenceOptions.None) +#endif // JAVA_INTEROP1 { } @@ -43,5 +44,3 @@ IEnumerator IEnumerable.GetEnumerator () } } } - -#endif // !JAVA_INTEROP1 diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt index 4593b88ef..1696f1528 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt @@ -11,6 +11,47 @@ public partial interface AnimatorListener : IJavaPeerable { } +[global::Java.Interop.JniTypeSignature ("java/code/AnimatorListener", GenerateJavaPeer=false)] +internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, AnimatorListener { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_code_AnimatorListener; } + } + + static readonly JniPeerMembers _members_java_code_AnimatorListener = new JniPeerMembers ("java/code/AnimatorListener", typeof (AnimatorListenerInvoker)); + + public AnimatorListenerInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool OnAnimationEnd (int param1) + { + const string __id = "OnAnimationEnd.(I)Z"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (param1); + var __rm = _members_java_code_AnimatorListener.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + } + } + + public unsafe bool OnAnimationEnd (int param1, int param2) + { + const string __id = "OnAnimationEnd.(II)Z"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [2]; + __args [0] = new JniArgumentValue (param1); + __args [1] = new JniArgumentValue (param2); + var __rm = _members_java_code_AnimatorListener.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + } + } + +} + // event args for java.code.AnimatorListener.OnAnimationEnd public partial class AnimationEndEventArgs : global::System.EventArgs { bool handled; diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt index 03ba73bfe..8649e3029 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt @@ -79,3 +79,114 @@ public partial interface IMyInterface : IJavaPeerable { } } + +[global::Java.Interop.JniTypeSignature ("java/code/IMyInterface", GenerateJavaPeer=false)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_code_IMyInterface; } + } + + static readonly JniPeerMembers _members_java_code_IMyInterface = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + public IMyInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe int Count { + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe string? Key { + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + public unsafe int AbstractCount { + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe int GetCountForKey (string? key) + { + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + var native_key = global::Java.Interop.JniEnvironment.Strings.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_key); + } + } + + public unsafe string? Key () + { + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + public unsafe void AbstractMethod () + { + const string __id = "AbstractMethod.()V"; + try { + _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs index a54dc94a6..65ea9d8a4 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs @@ -37,6 +37,7 @@ protected virtual CodeGenerationOptions CreateOptions () { return new CodeGenerationOptions { CodeGenerationTarget = Target, + EmitLegacyInterfaceInvokers = Target == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1, }; } diff --git a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs index b2018ed52..3ea50e6bd 100644 --- a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs +++ b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs @@ -16,4 +16,40 @@ public partial interface IExtendedInterface : IJavaPeerable { void BaseMethod (); } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/ExtendedInterface", GenerateJavaPeer=false)] + internal partial class IExtendedInterfaceInvoker : global::Java.Lang.Object, IExtendedInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_ExtendedInterface; } + } + + static readonly JniPeerMembers _members_xamarin_test_BaseInterface = new JniPeerMembers ("xamarin/test/BaseInterface", typeof (IExtendedInterfaceInvoker)); + + static readonly JniPeerMembers _members_xamarin_test_ExtendedInterface = new JniPeerMembers ("xamarin/test/ExtendedInterface", typeof (IExtendedInterfaceInvoker)); + + public IExtendedInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void ExtendedMethod () + { + const string __id = "extendedMethod.()V"; + try { + _members_xamarin_test_ExtendedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + public unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members_xamarin_test_BaseInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs index 59729bf4f..85af61586 100644 --- a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs +++ b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs @@ -26,6 +26,31 @@ protected internal partial interface IProtectedInterface : IJavaPeerable { } + [global::Java.Interop.JniTypeSignature ("xamarin/test/PublicClass$ProtectedInterface", GenerateJavaPeer=false)] + internal partial class IProtectedInterfaceInvoker : global::Java.Lang.Object, IProtectedInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_PublicClass_ProtectedInterface; } + } + + static readonly JniPeerMembers _members_xamarin_test_PublicClass_ProtectedInterface = new JniPeerMembers ("xamarin/test/PublicClass$ProtectedInterface", typeof (IProtectedInterfaceInvoker)); + + public IProtectedInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members_xamarin_test_PublicClass_ProtectedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/PublicClass", typeof (PublicClass)); [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] diff --git a/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs b/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs index 0d0b92994..97482afbc 100644 --- a/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs +++ b/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs @@ -12,4 +12,29 @@ public partial interface II1 : IJavaPeerable { void Close (); } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/I1", GenerateJavaPeer=false)] + internal partial class II1Invoker : global::Java.Lang.Object, II1 { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I1; } + } + + static readonly JniPeerMembers _members_xamarin_test_I1 = new JniPeerMembers ("xamarin/test/I1", typeof (II1Invoker)); + + public II1Invoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I1.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs b/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs index 9a91d592f..2d32246ec 100644 --- a/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs +++ b/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs @@ -12,4 +12,29 @@ public partial interface II2 : IJavaPeerable { void Close (); } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/I2", GenerateJavaPeer=false)] + internal partial class II2Invoker : global::Java.Lang.Object, II2 { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I2; } + } + + static readonly JniPeerMembers _members_xamarin_test_I2 = new JniPeerMembers ("xamarin/test/I2", typeof (II2Invoker)); + + public II2Invoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I2.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs b/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs new file mode 100644 index 000000000..363f3fe78 --- /dev/null +++ b/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +// Metadata.xml XPath class reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']" +[global::Java.Interop.JniTypeSignature ("ClassWithoutNamespace", GenerateJavaPeer=false)] +public abstract partial class ClassWithoutNamespace : global::Java.Lang.Object, IInterfaceWithoutNamespace { + static readonly JniPeerMembers _members = new JniPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespace)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected ClassWithoutNamespace (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']/constructor[@name='ClassWithoutNamespace' and count(parameter)=0]" + public unsafe ClassWithoutNamespace () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + public abstract void Foo (); + +} + +[global::Java.Interop.JniTypeSignature ("ClassWithoutNamespace", GenerateJavaPeer=false)] +internal partial class ClassWithoutNamespaceInvoker : ClassWithoutNamespace { + public ClassWithoutNamespaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespaceInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Foo", "()V")] + public override unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs b/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs new file mode 100644 index 000000000..76cfd4640 --- /dev/null +++ b/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +// Metadata.xml XPath interface reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']" +[global::Java.Interop.JniTypeSignature ("InterfaceWithoutNamespace", GenerateJavaPeer=false)] +public partial interface IInterfaceWithoutNamespace : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Foo", "()V")] + void Foo (); + +} + +[global::Java.Interop.JniTypeSignature ("InterfaceWithoutNamespace", GenerateJavaPeer=false)] +internal partial class IInterfaceWithoutNamespaceInvoker : global::Java.Lang.Object, IInterfaceWithoutNamespace { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members__InterfaceWithoutNamespace; } + } + + static readonly JniPeerMembers _members__InterfaceWithoutNamespace = new JniPeerMembers ("InterfaceWithoutNamespace", typeof (IInterfaceWithoutNamespaceInvoker)); + + public IInterfaceWithoutNamespaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members__InterfaceWithoutNamespace.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs b/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs index 86d0bd17b..47f7f2661 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; diff --git a/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs b/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs index 4cf8f3b23..5195f63f5 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; diff --git a/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs new file mode 100644 index 000000000..961586dbf --- /dev/null +++ b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Collection']" + [global::Java.Interop.JniTypeSignature ("java/util/Collection", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface ICollection : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='clear' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("clear", "()V")] + void Clear (); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Collection", GenerateJavaPeer=false)] + internal partial class ICollectionInvoker : global::Java.Lang.Object, ICollection { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Collection; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (ICollectionInvoker)); + + public ICollectionInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Collection.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs new file mode 100644 index 000000000..42f3b0623 --- /dev/null +++ b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Deque']" + [global::Java.Interop.JniTypeSignature ("java/util/Deque", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IDeque : global::Java.Util.IQueue { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Deque']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Deque", GenerateJavaPeer=false)] + internal partial class IDequeInvoker : global::Java.Lang.Object, IDeque { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Deque; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Deque = new JniPeerMembers ("java/util/Deque", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new JniPeerMembers ("java/util/Queue", typeof (IDequeInvoker)); + + public IDequeInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Deque.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs new file mode 100644 index 000000000..37ce2e920 --- /dev/null +++ b/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Queue']" + [global::Java.Interop.JniTypeSignature ("java/util/Queue", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IQueue : global::Java.Util.ICollection { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Queue']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Queue", GenerateJavaPeer=false)] + internal partial class IQueueInvoker : global::Java.Lang.Object, IQueue { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Queue; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (IQueueInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new JniPeerMembers ("java/util/Queue", typeof (IQueueInvoker)); + + public IQueueInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Queue.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems b/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems index 543e7917a..579227fee 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems +++ b/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems @@ -9,6 +9,9 @@ + + + diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs index 57548f289..d576431fe 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; @@ -36,14 +46,19 @@ public unsafe GenericImplementation () : base (ref *InvalidJniObjectReference, J } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "([B)V")] public virtual unsafe void SetObject (global::Java.Interop.JavaSByteArray value) { const string __id = "SetObject.([B)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (value); try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; - __args [0] = new JniArgumentValue (value); + __args [0] = new JniArgumentValue (native_value); _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } global::System.GC.KeepAlive (value); } } @@ -51,7 +66,7 @@ public virtual unsafe void SetObject (global::Java.Interop.JavaSByteArray value) // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericInterface void global::Test.ME.IGenericInterface.SetObject (global::Java.Lang.Object value) { - SetObject (global::Java.Interop.JavaObjectExtensions.JavaCast(value)); + SetObject (global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue((value?.PeerReference ?? default).Handle)); } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs index f9eaaf0a1..ffd79fa17 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs index 980f0f8c1..d629242ca 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; @@ -36,14 +46,19 @@ public unsafe GenericStringImplementation () : base (ref *InvalidJniObjectRefere } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='java.lang.String[]']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "([Ljava/lang/String;)V")] public virtual unsafe void SetObject (global::Java.Interop.JavaObjectArray value) { const string __id = "SetObject.([Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalObjectArray (value); try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; - __args [0] = new JniArgumentValue (value); + __args [0] = new JniArgumentValue (native_value); _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } global::System.GC.KeepAlive (value); } } @@ -51,7 +66,7 @@ public virtual unsafe void SetObject (global::Java.Interop.JavaObjectArray>(value)); + SetObject (global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue>((value?.PeerReference ?? default).Handle)); } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs index 4d1a64e6c..d32a3bb0f 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; @@ -62,11 +72,9 @@ public virtual unsafe string Object { // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericPropertyInterface global::Java.Lang.Object global::Test.ME.IGenericPropertyInterface.Object { // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" - [Register ("getObject", "()Ljava/lang/Object;", "GetGetObjectHandler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] - get { return Object; } + get { return new Java.Lang.String (Object); } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" - [Register ("setObject", "(Ljava/lang/Object;)V", "GetSetObject_Ljava_lang_Object_Handler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] - set { Object = value.ToString (); } + set { Object = value?.ToString (); } } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs index 148fbb718..bb76502da 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs @@ -9,7 +9,37 @@ namespace Test.ME { [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] public partial interface IGenericInterface : IJavaPeerable { // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericInterface']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "(Ljava/lang/Object;)V")] void SetObject (global::Java.Lang.Object value); } + + [global::Java.Interop.JniTypeSignature ("test/me/GenericInterface", GenerateJavaPeer=false)] + internal partial class IGenericInterfaceInvoker : global::Java.Lang.Object, IGenericInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericInterface; } + } + + static readonly JniPeerMembers _members_test_me_GenericInterface = new JniPeerMembers ("test/me/GenericInterface", typeof (IGenericInterfaceInvoker)); + + public IGenericInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void SetObject (global::Java.Lang.Object value) + { + const string __id = "SetObject.(Ljava/lang/Object;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs index cb88559ca..26b734b99 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs @@ -10,11 +10,51 @@ namespace Test.ME { public partial interface IGenericPropertyInterface : IJavaPeerable { global::Java.Lang.Object Object { // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getObject", "()Ljava/lang/Object;")] get; // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("setObject", "(Ljava/lang/Object;)V")] set; } } + + [global::Java.Interop.JniTypeSignature ("test/me/GenericPropertyInterface", GenerateJavaPeer=false)] + internal partial class IGenericPropertyInterfaceInvoker : global::Java.Lang.Object, IGenericPropertyInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericPropertyInterface; } + } + + static readonly JniPeerMembers _members_test_me_GenericPropertyInterface = new JniPeerMembers ("test/me/GenericPropertyInterface", typeof (IGenericPropertyInterfaceInvoker)); + + public IGenericPropertyInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe global::Java.Lang.Object Object { + get { + const string __id = "getObject.()Ljava/lang/Object;"; + try { + var __rm = _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + set { + const string __id = "setObject.(Ljava/lang/Object;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs index 809216acb..2e5f90151 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs @@ -4,49 +4,19 @@ namespace Test.ME { - [Register ("test/me/TestInterface", DoNotGenerateAcw=true)] - public abstract class TestInterface : Java.Lang.Object { - internal TestInterface () - { - } - - // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='SPAN_COMPOSING']" - public const int SpanComposing = (int) 256; - - - // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='DEFAULT_FOO']" - public static global::Java.Lang.Object DefaultFoo { - get { - const string __id = "DEFAULT_FOO.Ljava/lang/Object;"; - - var __v = _members.StaticFields.GetObjectValue (__id); - return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __v.Handle, JniObjectReferenceOptions.CopyAndDispose); - } - } - - static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/TestInterface", typeof (TestInterface)); - - } - - [Register ("test/me/TestInterface", DoNotGenerateAcw=true)] - [global::System.Obsolete ("Use the 'TestInterface' type. This type will be removed in a future release.", error: true)] - public abstract class TestInterfaceConsts : TestInterface { - private TestInterfaceConsts () - { - } - - } - // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']" [global::Java.Interop.JniTypeSignature ("test/me/TestInterface", GenerateJavaPeer=false)] public partial interface ITestInterface : IJavaPeerable { // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("getSpanFlags", "(Ljava/lang/Object;)I")] int GetSpanFlags (global::Java.Lang.Object tag); // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("append", "(Ljava/lang/CharSequence;)V")] void Append (global::Java.Lang.ICharSequence value); // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;")] global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); } @@ -69,4 +39,58 @@ public static string Identity (this Test.ME.ITestInterface self, string value) } } + + [global::Java.Interop.JniTypeSignature ("test/me/TestInterface", GenerateJavaPeer=false)] + internal partial class ITestInterfaceInvoker : global::Java.Lang.Object, ITestInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_TestInterface; } + } + + static readonly JniPeerMembers _members_test_me_TestInterface = new JniPeerMembers ("test/me/TestInterface", typeof (ITestInterfaceInvoker)); + + public ITestInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe int GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (tag); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + public unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_test_me_TestInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + + public unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + global::System.GC.KeepAlive (value); + } + } + + } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs index e1d682227..de65e056f 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs +++ b/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs @@ -1,3 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore using System; using System.Collections.Generic; using Java.Interop; @@ -20,7 +30,7 @@ public static class InterfaceConsts { const string __id = "DEFAULT_FOO.Ljava/lang/Object;"; var __v = _members.StaticFields.GetObjectValue (__id); - return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __v.Handle, JniObjectReferenceOptions.CopyAndDispose); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); } } @@ -96,6 +106,7 @@ public TestInterfaceImplementationInvoker (ref JniObjectReference reference, Jni } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("getSpanFlags", "(Ljava/lang/Object;)I")] public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) { const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; @@ -110,32 +121,30 @@ public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("append", "(Ljava/lang/CharSequence;)V")] public override unsafe void Append (global::Java.Lang.ICharSequence value) { const string __id = "append.(Ljava/lang/CharSequence;)V"; - IntPtr native_value = CharSequence.ToLocalJniHandle (value); try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; - __args [0] = new JniArgumentValue (native_value); + __args [0] = new JniArgumentValue (value); _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); } finally { - JNIEnv.DeleteLocalRef (native_value); global::System.GC.KeepAlive (value); } } // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;")] public override unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) { const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; - IntPtr native_value = CharSequence.ToLocalJniHandle (value); try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; - __args [0] = new JniArgumentValue (native_value); + __args [0] = new JniArgumentValue (value); var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); - return global::Java.Lang.Object.GetObject (__rm, JniHandleOwnership.TransferLocalRef); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); } finally { - JNIEnv.DeleteLocalRef (native_value); global::System.GC.KeepAlive (value); } } diff --git a/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml b/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml index 0357601e7..bbaa4e207 100644 --- a/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml +++ b/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml @@ -7,6 +7,41 @@ final="true" name="String" static="false" visibility="public"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +