From eff56ddc05a40144134b836e6ba7bfbb4a977f59 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 17 Dec 2024 15:00:16 -0600 Subject: [PATCH] [Mono.Android] `Java.Lang.Object.GetObject()` implementation The current implementation: return Java.Interop.TypeManager.CreateInstance (handle, transfer, type); Needs to become this, for NativeAOT support: JniObjectReference reference = new (handle); JniObjectReferenceOptions options = JNIEnv.ToJniObjectReferenceOptions (transfer); return (IJavaPeerable) JNIEnvInit.AndroidValueManager?.GetValue (ref reference, options, type); This way we use the appropriate `AndroidValueManager` for the runtime that is currently being used. If we just change the code in `Java.Lang.Object` to do this for all runtimes, this can keep everything a bit simpler. The fallout of this change requires `type` to be decorated with: [DynamicallyAccessedMembers (ConstructorsInterfaces)] This trickled to create many other trimmer warnings, that are likely a real issue. This is a good opportunity to fix them. I also defined the `const` values in `Java.Lang.Object`: internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; internal const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; Which allowed many types that extend `Java.Lang.Object` able to reuse these `const` values and not define them again. I also had to make a helper function to map `JniHandleOwnership` -> `JniObjectReferenceOptions`, such as: internal static JniObjectReferenceOptions ToJniObjectReferenceOptions (JniHandleOwnership transfer) --- src/Mono.Android/Android.App/Activity.cs | 6 ++-- src/Mono.Android/Android.App/Dialog.cs | 2 +- .../Android.App/FragmentManager.cs | 8 ++--- src/Mono.Android/Android.OS/AsyncTask.cs | 8 ++--- .../Android.Runtime/Extensions.cs | 2 +- src/Mono.Android/Android.Runtime/JNIEnv.cs | 29 +++++++++++++++++-- src/Mono.Android/Android.Runtime/JavaArray.cs | 7 +++-- .../Android.Runtime/JavaCollection.cs | 6 ++-- .../Android.Runtime/JavaDictionary.cs | 6 ++-- src/Mono.Android/Android.Runtime/JavaList.cs | 7 ++--- src/Mono.Android/Android.Runtime/JavaSet.cs | 2 +- src/Mono.Android/Android.Util/SparseArray.cs | 2 +- src/Mono.Android/Android.Views/View.cs | 7 ++--- src/Mono.Android/Android.Views/Window.cs | 2 +- .../Android.Widget/AdapterView.cs | 2 +- .../Android.Widget/ArrayAdapter.cs | 2 +- src/Mono.Android/Java.Interop/JavaConvert.cs | 13 +++++---- .../Java.Interop/JavaObjectExtensions.cs | 15 +++++----- src/Mono.Android/Java.Lang/Object.cs | 28 ++++++++++++++---- src/Mono.Android/System.Linq/Extensions.cs | 5 ++-- .../api-compat-exclude-attributes.txt | 1 + 21 files changed, 97 insertions(+), 63 deletions(-) diff --git a/src/Mono.Android/Android.App/Activity.cs b/src/Mono.Android/Android.App/Activity.cs index dd881a6b539..07da31bda16 100644 --- a/src/Mono.Android/Android.App/Activity.cs +++ b/src/Mono.Android/Android.App/Activity.cs @@ -6,10 +6,8 @@ namespace Android.App { partial class Activity { - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - public T? FindViewById< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View @@ -19,7 +17,7 @@ public T? FindViewById< // See: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/Activity.java;l=3430 public T RequireViewById< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View diff --git a/src/Mono.Android/Android.App/Dialog.cs b/src/Mono.Android/Android.App/Dialog.cs index 2a1a1f10ce8..e4e839e67e7 100644 --- a/src/Mono.Android/Android.App/Dialog.cs +++ b/src/Mono.Android/Android.App/Dialog.cs @@ -10,7 +10,7 @@ protected Dialog (Android.Content.Context context, bool cancelable, EventHandler : this (context, cancelable, new Android.Content.IDialogInterfaceOnCancelListenerImplementor () { Handler = cancelHandler }) {} public T? FindViewById< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View diff --git a/src/Mono.Android/Android.App/FragmentManager.cs b/src/Mono.Android/Android.App/FragmentManager.cs index 5269111a1a0..c679d97e8b3 100644 --- a/src/Mono.Android/Android.App/FragmentManager.cs +++ b/src/Mono.Android/Android.App/FragmentManager.cs @@ -5,10 +5,8 @@ #if ANDROID_11 namespace Android.App { public partial class FragmentManager { - const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - public T? FindFragmentById< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Fragment @@ -17,7 +15,7 @@ public T? FindFragmentById< } public T? FindFragmentByTag< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (string tag) where T : Fragment @@ -26,7 +24,7 @@ public T? FindFragmentByTag< } public T? GetFragment< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (Bundle bundle, string key) where T : Fragment diff --git a/src/Mono.Android/Android.OS/AsyncTask.cs b/src/Mono.Android/Android.OS/AsyncTask.cs index 7dcb9049b6f..9999efd3755 100644 --- a/src/Mono.Android/Android.OS/AsyncTask.cs +++ b/src/Mono.Android/Android.OS/AsyncTask.cs @@ -10,16 +10,14 @@ namespace Android.OS { [global::System.Runtime.Versioning.ObsoletedOSPlatform ("android30.0")] [Register ("android/os/AsyncTask", DoNotGenerateAcw=true)] public abstract class AsyncTask< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] TParams, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] TProgress, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] TResult > : AsyncTask { - const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - static IntPtr java_class_handle; internal static IntPtr class_ref { get { diff --git a/src/Mono.Android/Android.Runtime/Extensions.cs b/src/Mono.Android/Android.Runtime/Extensions.cs index 2d41fa03e2b..f9a10faf183 100644 --- a/src/Mono.Android/Android.Runtime/Extensions.cs +++ b/src/Mono.Android/Android.Runtime/Extensions.cs @@ -8,7 +8,7 @@ public static class Extensions { [return: NotNullIfNotNull ("instance")] public static TResult? JavaCast< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.Interfaces)] TResult > (this IJavaObject? instance) where TResult : class, IJavaObject diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 9d6ba857379..7372e19afb2 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -17,6 +17,7 @@ namespace Android.Runtime { public static partial class JNIEnv { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; [ThreadStatic] static byte[]? mvid_bytes; @@ -322,6 +323,21 @@ public static IntPtr FindClass (System.Type type) } } + internal static JniObjectReferenceOptions ToJniObjectReferenceOptions (JniHandleOwnership transfer) + { + switch (transfer) { + case JniHandleOwnership.DoNotTransfer: + return JniObjectReferenceOptions.Copy; + case JniHandleOwnership.TransferGlobalRef: + case JniHandleOwnership.TransferLocalRef: + return JniObjectReferenceOptions.CopyAndDispose; + case JniHandleOwnership.DoNotRegister: + return JniObjectReferenceOptions.CopyAndDoNotRegister; + default: + throw new ArgumentOutOfRangeException (nameof (transfer), transfer, "Invalid JniHandleOwnership value."); + } + } + const int nameBufferLength = 1024; [ThreadStatic] static char[]? nameBuffer; @@ -704,7 +720,14 @@ public static void CopyArray (IntPtr src, string[] dest) AssertIsJavaObject (type); IntPtr elem = GetObjectArrayElement (source, index); - return Java.Lang.Object.GetObject (elem, JniHandleOwnership.TransferLocalRef, type); + return GetObject (elem, type); + + // FIXME: https://github.com/xamarin/xamarin-android/issues/8724 + // Since a Dictionary is used here, the trimmer will not be able to properly analyze `Type t` + // error IL2111: Method 'lambda expression' with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + [UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "[DynamicallyAccessedMembers] manually added to all callers")] + static object? GetObject (IntPtr e, Type t) => + Java.Lang.Object.GetObject (e, JniHandleOwnership.TransferLocalRef, t); } }, { typeof (Array), (type, source, index) => { IntPtr elem = GetObjectArrayElement (source, index); @@ -1135,7 +1158,7 @@ static int _GetArrayLength (IntPtr array_ptr) } public static T[]? GetArray< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (Java.Lang.Object[] array) { @@ -1252,7 +1275,7 @@ static IntPtr GetArrayElementClass(T[] values) } public static void CopyObjectArray< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T >(IntPtr source, T[] destination) { diff --git a/src/Mono.Android/Android.Runtime/JavaArray.cs b/src/Mono.Android/Android.Runtime/JavaArray.cs index 4d05a7de4a3..1884129851e 100644 --- a/src/Mono.Android/Android.Runtime/JavaArray.cs +++ b/src/Mono.Android/Android.Runtime/JavaArray.cs @@ -1,12 +1,15 @@ using System; using System.Collections; using System.Collections.Generic; - +using System.Diagnostics.CodeAnalysis; namespace Android.Runtime { [Register ("mono/android/runtime/JavaArray", DoNotGenerateAcw=true)] - public sealed class JavaArray : Java.Lang.Object, IList { + public sealed class JavaArray< + [DynamicallyAccessedMembers (ConstructorsInterfaces)] + T + > : Java.Lang.Object, IList { public JavaArray (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) diff --git a/src/Mono.Android/Android.Runtime/JavaCollection.cs b/src/Mono.Android/Android.Runtime/JavaCollection.cs index 8e23660f33b..6e4aa38cef6 100644 --- a/src/Mono.Android/Android.Runtime/JavaCollection.cs +++ b/src/Mono.Android/Android.Runtime/JavaCollection.cs @@ -14,8 +14,6 @@ namespace Android.Runtime { // java.util.Collection allows null values public class JavaCollection : Java.Lang.Object, System.Collections.ICollection { - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - internal static IntPtr collection_class = JNIEnv.FindClass ("java/util/Collection"); internal static IntPtr id_add; @@ -151,7 +149,7 @@ internal Java.Lang.Object[] ToArray () public void CopyTo (Array array, int array_index) { [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaCollection constructors are preserved by the MarkJavaObjects trimmer step.")] - [return: DynamicallyAccessedMembers (Constructors)] + [return: DynamicallyAccessedMembers (ConstructorsInterfaces)] static Type GetElementType (Array array) => array.GetType ().GetElementType (); @@ -211,7 +209,7 @@ public static IntPtr ToLocalJniHandle (ICollection? items) [Register ("java/util/Collection", DoNotGenerateAcw=true)] public sealed class JavaCollection< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > : JavaCollection, ICollection { diff --git a/src/Mono.Android/Android.Runtime/JavaDictionary.cs b/src/Mono.Android/Android.Runtime/JavaDictionary.cs index 311dbf36ebe..739d86b2825 100644 --- a/src/Mono.Android/Android.Runtime/JavaDictionary.cs +++ b/src/Mono.Android/Android.Runtime/JavaDictionary.cs @@ -12,8 +12,6 @@ namespace Android.Runtime { // java.util.HashMap allows null keys and values public class JavaDictionary : Java.Lang.Object, System.Collections.IDictionary { - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - class DictionaryEnumerator : IDictionaryEnumerator { IEnumerator simple_enumerator; @@ -399,9 +397,9 @@ public static IntPtr ToLocalJniHandle (IDictionary? dictionary) // [Register ("java/util/HashMap", DoNotGenerateAcw=true)] public class JavaDictionary< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] K, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] V > : JavaDictionary, IDictionary { diff --git a/src/Mono.Android/Android.Runtime/JavaList.cs b/src/Mono.Android/Android.Runtime/JavaList.cs index e1877533577..c390b660ed7 100644 --- a/src/Mono.Android/Android.Runtime/JavaList.cs +++ b/src/Mono.Android/Android.Runtime/JavaList.cs @@ -10,7 +10,6 @@ namespace Android.Runtime { // java.util.ArrayList allows null values public partial class JavaList : Java.Lang.Object, System.Collections.IList { - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; internal static readonly JniPeerMembers list_members = new XAPeerMembers ("java/util/List", typeof (JavaList), isInterface: true); // @@ -26,7 +25,7 @@ public partial class JavaList : Java.Lang.Object, System.Collections.IList { // internal unsafe object? InternalGet ( int location, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] Type? targetType = null) { const string id = "get.(I)Ljava/lang/Object;"; @@ -271,7 +270,7 @@ public unsafe bool Contains (object? item) public void CopyTo (Array array, int array_index) { [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaList constructors are preserved by the MarkJavaObjects trimmer step.")] - [return: DynamicallyAccessedMembers (Constructors)] + [return: DynamicallyAccessedMembers (ConstructorsInterfaces)] static Type GetElementType (Array array) => array.GetType ().GetElementType (); @@ -683,7 +682,7 @@ public virtual Java.Lang.Object [] ToArray () [Register ("java/util/ArrayList", DoNotGenerateAcw=true)] public class JavaList< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > : JavaList, IList { diff --git a/src/Mono.Android/Android.Runtime/JavaSet.cs b/src/Mono.Android/Android.Runtime/JavaSet.cs index b84b040289a..d8ec4f4c754 100644 --- a/src/Mono.Android/Android.Runtime/JavaSet.cs +++ b/src/Mono.Android/Android.Runtime/JavaSet.cs @@ -269,7 +269,7 @@ public static IntPtr ToLocalJniHandle (ICollection? items) [Register ("java/util/HashSet", DoNotGenerateAcw=true)] // java.util.HashSet allows null public class JavaSet< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > : JavaSet, ICollection { diff --git a/src/Mono.Android/Android.Util/SparseArray.cs b/src/Mono.Android/Android.Util/SparseArray.cs index 2a895fb7307..8e1209236ad 100644 --- a/src/Mono.Android/Android.Util/SparseArray.cs +++ b/src/Mono.Android/Android.Util/SparseArray.cs @@ -9,7 +9,7 @@ namespace Android.Util { [Register ("android/util/SparseArray", DoNotGenerateAcw=true)] public partial class SparseArray< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] E > : SparseArray { diff --git a/src/Mono.Android/Android.Views/View.cs b/src/Mono.Android/Android.Views/View.cs index 5ef341f243b..525850da969 100644 --- a/src/Mono.Android/Android.Views/View.cs +++ b/src/Mono.Android/Android.Views/View.cs @@ -13,9 +13,6 @@ public enum SystemUiFlags { #endif public partial class View { - - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - #if ANDROID_16 [Obsolete ("This method uses wrong enum type. Please use PerformAccessibilityAction(Action) instead.")] public bool PerformAccessibilityAction (GlobalAction action, Bundle arguments) @@ -25,7 +22,7 @@ public bool PerformAccessibilityAction (GlobalAction action, Bundle arguments) #endif public T? FindViewById< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View @@ -35,7 +32,7 @@ public T? FindViewById< // See: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/View.java;l=25322 public T RequireViewById< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View diff --git a/src/Mono.Android/Android.Views/Window.cs b/src/Mono.Android/Android.Views/Window.cs index 1d82b614ec4..c833136aa00 100644 --- a/src/Mono.Android/Android.Views/Window.cs +++ b/src/Mono.Android/Android.Views/Window.cs @@ -7,7 +7,7 @@ namespace Android.Views { partial class Window { public T? FindViewById< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (int id) where T : Android.Views.View diff --git a/src/Mono.Android/Android.Widget/AdapterView.cs b/src/Mono.Android/Android.Widget/AdapterView.cs index 7689b0c39e3..5e1c3a57a3e 100644 --- a/src/Mono.Android/Android.Widget/AdapterView.cs +++ b/src/Mono.Android/Android.Widget/AdapterView.cs @@ -51,7 +51,7 @@ public event EventHandler ItemSelectionCleared { [Register ("android/widget/AdapterView", DoNotGenerateAcw=true)] public abstract class AdapterView< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > : AdapterView where T : IAdapter { diff --git a/src/Mono.Android/Android.Widget/ArrayAdapter.cs b/src/Mono.Android/Android.Widget/ArrayAdapter.cs index e54ce8d7c94..4faedac2189 100644 --- a/src/Mono.Android/Android.Widget/ArrayAdapter.cs +++ b/src/Mono.Android/Android.Widget/ArrayAdapter.cs @@ -9,7 +9,7 @@ namespace Android.Widget { [Register ("android/widget/ArrayAdapter", DoNotGenerateAcw=true)] public partial class ArrayAdapter< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > : ArrayAdapter { diff --git a/src/Mono.Android/Java.Interop/JavaConvert.cs b/src/Mono.Android/Java.Interop/JavaConvert.cs index e7602ba4432..0a02c89a508 100644 --- a/src/Mono.Android/Java.Interop/JavaConvert.cs +++ b/src/Mono.Android/Java.Interop/JavaConvert.cs @@ -11,6 +11,7 @@ namespace Java.Interop { static class JavaConvert { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; static Dictionary> JniHandleConverters = new Dictionary>() { { typeof (bool), (handle, transfer) => { @@ -109,7 +110,7 @@ static Func GetJniHandleConverterForType ([D } public static T? FromJniHandle< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T >(IntPtr handle, JniHandleOwnership transfer) { @@ -118,7 +119,7 @@ public static T? FromJniHandle< } public static T? FromJniHandle< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T >(IntPtr handle, JniHandleOwnership transfer, out bool set) { @@ -158,7 +159,7 @@ public static T? FromJniHandle< public static object? FromJniHandle ( IntPtr handle, JniHandleOwnership transfer, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] Type? targetType = null) { if (handle == IntPtr.Zero) { @@ -233,7 +234,7 @@ public static T? FromJniHandle< } public static T? FromJavaObject< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T >(IJavaObject? value) { @@ -242,7 +243,7 @@ public static T? FromJavaObject< } public static T? FromJavaObject< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T >(IJavaObject? value, out bool set) { @@ -279,7 +280,7 @@ public static T? FromJavaObject< public static object? FromJavaObject ( IJavaObject value, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] Type? targetType = null) { if (value == null) diff --git a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs index a3e817facb9..5146bc09c8f 100644 --- a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs +++ b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs @@ -9,6 +9,7 @@ namespace Java.Interop { public static class JavaObjectExtensions { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; [Obsolete ("Use Android.Runtime.JavaCollection.ToLocalJniHandle()")] public static JavaCollection ToInteroperableCollection (this ICollection instance) @@ -18,7 +19,7 @@ public static JavaCollection ToInteroperableCollection (this ICollection instanc [Obsolete ("Use Android.Runtime.JavaCollection.ToLocalJniHandle()")] public static JavaCollection ToInteroperableCollection< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (this ICollection instance) { @@ -33,7 +34,7 @@ public static JavaList ToInteroperableCollection (this IList instance) [Obsolete ("Use Android.Runtime.JavaList.ToLocalJniHandle()")] public static JavaList ToInteroperableCollection< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (this IList instance) { @@ -48,9 +49,9 @@ public static JavaDictionary ToInteroperableCollection (this IDictionary instanc [Obsolete ("Use Android.Runtime.JavaDictionary.ToLocalJniHandle()")] public static JavaDictionary ToInteroperableCollection< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] K, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] V > (this IDictionary instance) { @@ -59,7 +60,7 @@ public static JavaDictionary ToInteroperableCollection< [return: NotNullIfNotNull ("instance")] public static TResult? JavaCast< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] TResult > (this IJavaObject? instance) where TResult : class, IJavaObject @@ -68,7 +69,7 @@ public static TResult? JavaCast< } internal static TResult? _JavaCast< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] TResult > (this IJavaObject? instance) { @@ -88,7 +89,7 @@ internal static TResult? _JavaCast< internal static IJavaObject? JavaCast ( IJavaObject? instance, - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] Type resultType) { if (resultType == null) diff --git a/src/Mono.Android/Java.Lang/Object.cs b/src/Mono.Android/Java.Lang/Object.cs index 9df5b5bbee9..7b10a579599 100644 --- a/src/Mono.Android/Java.Lang/Object.cs +++ b/src/Mono.Android/Java.Lang/Object.cs @@ -19,6 +19,9 @@ public partial class Object : IDisposable, IJavaObject, IJavaObjectEx , IJavaPeerable #endif // JAVA_INTEROP { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + internal const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; + [NonSerialized] IntPtr key_handle; #pragma warning disable CS0649, CS0169, CS0414 // Suppress fields are never used warnings, these fields are used directly by monodroid-glue.cc [NonSerialized] int refs_added; @@ -263,20 +266,29 @@ protected void SetHandle (IntPtr value, JniHandleOwnership transfer) return (T?)PeekObject (handle, typeof (T)); } - public static T? GetObject (IntPtr jnienv, IntPtr handle, JniHandleOwnership transfer) + public static T? GetObject< + [DynamicallyAccessedMembers (ConstructorsInterfaces)] + T + > (IntPtr jnienv, IntPtr handle, JniHandleOwnership transfer) where T : class, IJavaObject { JNIEnv.CheckHandle (jnienv); return GetObject (handle, transfer); } - public static T? GetObject (IntPtr handle, JniHandleOwnership transfer) + public static T? GetObject< + [DynamicallyAccessedMembers (ConstructorsInterfaces)] + T + > (IntPtr handle, JniHandleOwnership transfer) where T : class, IJavaObject { return _GetObject(handle, transfer); } - internal static T? _GetObject (IntPtr handle, JniHandleOwnership transfer) + internal static T? _GetObject< + [DynamicallyAccessedMembers (ConstructorsInterfaces)] + T + > (IntPtr handle, JniHandleOwnership transfer) { if (handle == IntPtr.Zero) return default (T); @@ -284,7 +296,11 @@ protected void SetHandle (IntPtr value, JniHandleOwnership transfer) return (T?) GetObject (handle, transfer, typeof (T)); } - internal static IJavaPeerable? GetObject (IntPtr handle, JniHandleOwnership transfer, Type? type = null) + internal static IJavaPeerable? GetObject ( + IntPtr handle, + JniHandleOwnership transfer, + [DynamicallyAccessedMembers (ConstructorsInterfaces)] + Type? type = null) { if (handle == IntPtr.Zero) return null; @@ -295,7 +311,9 @@ protected void SetHandle (IntPtr value, JniHandleOwnership transfer) return r; } - return Java.Interop.TypeManager.CreateInstance (handle, transfer, type); + JniObjectReference reference = new (handle); + JniObjectReferenceOptions options = JNIEnv.ToJniObjectReferenceOptions (transfer); + return (IJavaPeerable) JNIEnvInit.AndroidValueManager?.GetValue (ref reference, options, type); } [EditorBrowsable (EditorBrowsableState.Never)] diff --git a/src/Mono.Android/System.Linq/Extensions.cs b/src/Mono.Android/System.Linq/Extensions.cs index c8bb0a4a740..08b55de7c30 100644 --- a/src/Mono.Android/System.Linq/Extensions.cs +++ b/src/Mono.Android/System.Linq/Extensions.cs @@ -10,6 +10,7 @@ namespace System.Linq { public static class Extensions { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + const DynamicallyAccessedMemberTypes ConstructorsInterfaces = Constructors | DynamicallyAccessedMemberTypes.Interfaces; static IntPtr id_next; @@ -43,7 +44,7 @@ internal static IEnumerator ToEnumerator_Dispose (this Java.Util.IIterator sourc } public static IEnumerable ToEnumerable< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (this Java.Lang.IIterable source) { @@ -58,7 +59,7 @@ public static IEnumerable ToEnumerable< } internal static IEnumerator ToEnumerator_Dispose< - [DynamicallyAccessedMembers (Constructors)] + [DynamicallyAccessedMembers (ConstructorsInterfaces)] T > (this Java.Util.IIterator source) { diff --git a/tests/api-compatibility/api-compat-exclude-attributes.txt b/tests/api-compatibility/api-compat-exclude-attributes.txt index bb1d43bbe88..0ca120ff8dd 100644 --- a/tests/api-compatibility/api-compat-exclude-attributes.txt +++ b/tests/api-compatibility/api-compat-exclude-attributes.txt @@ -16,3 +16,4 @@ T:System.Runtime.CompilerServices.IteratorStateMachineAttribute T:System.Runtime.CompilerServices.NullableAttribute T:System.Runtime.CompilerServices.NullableContextAttribute T:System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute +T:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute