From b5d144071923810db75cde5e84f7f93308786189 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 23 Jun 2026 18:51:17 +0200 Subject: [PATCH 1/8] Remove unnecessary DAM attributes Remove DynamicallyAccessedMembers annotations from runtime extensibility points where broad rooting is more harmful than useful. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../NativeAotTypeManager.cs | 7 -- .../NativeAotTypeManager.cs | 6 -- src/Java.Interop/Java.Interop/JavaArray.cs | 6 +- .../Java.Interop/JavaObjectArray.cs | 7 +- .../Java.Interop/JavaPrimitiveArrays.cs | 15 ---- .../Java.Interop/JniBuiltinMarshalers.cs | 75 +++++++------------ .../Java.Interop/JniRuntime.JniTypeManager.cs | 50 ++----------- .../JniRuntime.JniValueManager.cs | 24 ++---- .../JniRuntime.ReflectionJniTypeManager.cs | 40 ++-------- .../JniRuntime.ReflectionJniValueManager.cs | 34 +++------ .../Java.Interop/JniStringValueMarshaler.cs | 1 - .../Java.Interop/JniValueMarshaler.cs | 12 +-- src/Java.Interop/Java.Interop/ManagedPeer.cs | 9 +-- .../Java.Interop/RuntimeFeature.cs | 7 +- src/Java.Interop/PublicAPI.Unshipped.txt | 5 -- .../Java.Interop/JreTypeManager.cs | 1 - 16 files changed, 65 insertions(+), 234 deletions(-) diff --git a/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs b/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs index 42010c449..466acabbe 100644 --- a/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs +++ b/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs @@ -15,12 +15,6 @@ namespace Java.Interop.Samples.NativeAotFromAndroid; // suppressions lived (buried) inside JniTypeManager itself, justified "NotUsedInAndroid"; #1441 just // moved that responsibility to callers via [RequiresDynamicCode]/[RequiresUnreferencedCode]. partial class NativeAotTypeManager : JniRuntime.ReflectionJniTypeManager { - - const DynamicallyAccessedMemberTypes MethodsConstructors = - DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - Dictionary typeMappings = new () { ["android/app/Activity"] = typeof (Android.App.Activity), ["android/content/Context"] = typeof (Android.Content.Context), @@ -39,7 +33,6 @@ public NativeAotTypeManager () // GetType() dispatches through GetTypeForSimpleReference (singular), so the sample's own type // map has to be applied here; the base ReflectionJniTypeManager only knows the built-in types. - [return: DynamicallyAccessedMembers (MethodsConstructors)] protected override Type? GetTypeForSimpleReference (string jniSimpleReference) { if (typeMappings.TryGetValue (jniSimpleReference, out var target)) diff --git a/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs b/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs index 3dbea075f..a3b3006a3 100644 --- a/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs +++ b/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs @@ -16,11 +16,6 @@ namespace Hello_NativeAOTFromJNI; // moved that responsibility to callers via [RequiresDynamicCode]/[RequiresUnreferencedCode]. class NativeAotTypeManager : JniRuntime.ReflectionJniTypeManager { - const DynamicallyAccessedMemberTypes MethodsConstructors = - DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Sample only (see class comment): this assembly is rooted via TrimmerRootAssembly and the members reflected over during registration are preserved by the [DynamicallyAccessedMembers] annotations on the RegisterNativeMembers(Type) -> FindAndCallRegisterMethod path, so trimming does not remove what reflection needs.")] [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Sample only (see class comment): built-in member registration calls CreateDelegate on compile-time-known static methods (no MakeGenericType / expression compilation), so no runtime code generation is required.")] public NativeAotTypeManager () @@ -31,7 +26,6 @@ public NativeAotTypeManager () // JavaProxyObject, ...) and handles registration and the reverse Type->JNI mapping (via the // [JniTypeSignature] attribute) for us. We only need to teach it about this sample's own // managed types. - [return: DynamicallyAccessedMembers (MethodsConstructors)] protected override Type? GetTypeForSimpleReference (string jniSimpleReference) { if (jniSimpleReference == Example.ManagedType.JniTypeName) diff --git a/src/Java.Interop/Java.Interop/JavaArray.cs b/src/Java.Interop/Java.Interop/JavaArray.cs index 61f2b5f1e..c7dd8cdd6 100644 --- a/src/Java.Interop/Java.Interop/JavaArray.cs +++ b/src/Java.Interop/Java.Interop/JavaArray.cs @@ -364,11 +364,7 @@ public void Dispose () } [JniTypeSignature ("java/lang/Object", ArrayRank=1, GenerateJavaPeer=false)] - public abstract class JavaPrimitiveArray< - [DynamicallyAccessedMembers (Constructors)] - T - > - : JavaArray + public abstract class JavaPrimitiveArray : JavaArray { internal JavaPrimitiveArray (ref JniObjectReference reference, JniObjectReferenceOptions transfer) diff --git a/src/Java.Interop/Java.Interop/JavaObjectArray.cs b/src/Java.Interop/Java.Interop/JavaObjectArray.cs index 5e9e439e2..b7c437365 100644 --- a/src/Java.Interop/Java.Interop/JavaObjectArray.cs +++ b/src/Java.Interop/Java.Interop/JavaObjectArray.cs @@ -8,11 +8,7 @@ namespace Java.Interop { [JniTypeSignature ("java/lang/Object", ArrayRank=1, GenerateJavaPeer=false)] - public class JavaObjectArray< - [DynamicallyAccessedMembers (Constructors)] - T - > - : JavaArray + public class JavaObjectArray<[DynamicallyAccessedMembers (Constructors)] T> : JavaArray { internal static readonly ValueMarshaler Instance = new ValueMarshaler (); @@ -171,7 +167,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue (ref reference, options, targetType, (ref JniObjectReference h, JniObjectReferenceOptions t) => new JavaObjectArray (ref h, t) { diff --git a/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs b/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs index a7f06c76f..c2bd6e010 100644 --- a/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs +++ b/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs @@ -245,7 +245,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -256,7 +255,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -449,7 +447,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -460,7 +457,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -653,7 +649,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -664,7 +659,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -868,7 +862,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -1061,7 +1054,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -1072,7 +1064,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -1265,7 +1256,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -1276,7 +1266,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -1469,7 +1458,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -1480,7 +1468,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( @@ -1673,7 +1660,6 @@ internal override bool TargetTypeIsCurrentType (Type? targetType) public static object? CreateMarshaledValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return ArrayMarshaler.CreateValue (handle, targetType); @@ -1684,7 +1670,6 @@ internal sealed class ValueMarshaler : JniValueMarshaler> { public override IList CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JavaArray.CreateValue ( diff --git a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs index 49e70cc31..f51f6b2e8 100644 --- a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs +++ b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs @@ -153,30 +153,33 @@ static Dictionary InitJniBuiltinSimpleReferenceToType () }; } - static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); - - static KeyValuePair[] InitJniBuiltinMarshalers () - { - return new []{ - new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), - new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), - new KeyValuePair(typeof (Boolean), JniBooleanValueMarshaler.Instance), - new KeyValuePair(typeof (Boolean?), JniNullableBooleanValueMarshaler.Instance), - new KeyValuePair(typeof (SByte), JniSByteValueMarshaler.Instance), - new KeyValuePair(typeof (SByte?), JniNullableSByteValueMarshaler.Instance), - new KeyValuePair(typeof (Char), JniCharValueMarshaler.Instance), - new KeyValuePair(typeof (Char?), JniNullableCharValueMarshaler.Instance), - new KeyValuePair(typeof (Int16), JniInt16ValueMarshaler.Instance), - new KeyValuePair(typeof (Int16?), JniNullableInt16ValueMarshaler.Instance), - new KeyValuePair(typeof (Int32), JniInt32ValueMarshaler.Instance), - new KeyValuePair(typeof (Int32?), JniNullableInt32ValueMarshaler.Instance), - new KeyValuePair(typeof (Int64), JniInt64ValueMarshaler.Instance), - new KeyValuePair(typeof (Int64?), JniNullableInt64ValueMarshaler.Instance), - new KeyValuePair(typeof (Single), JniSingleValueMarshaler.Instance), - new KeyValuePair(typeof (Single?), JniNullableSingleValueMarshaler.Instance), - new KeyValuePair(typeof (Double), JniDoubleValueMarshaler.Instance), - new KeyValuePair(typeof (Double?), JniNullableDoubleValueMarshaler.Instance), - }; + partial class ReflectionJniValueManager + { + static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); + + static KeyValuePair[] InitJniBuiltinMarshalers () + { + return new []{ + new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), + new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), + new KeyValuePair(typeof (Boolean), JniBooleanValueMarshaler.Instance), + new KeyValuePair(typeof (Boolean?), JniNullableBooleanValueMarshaler.Instance), + new KeyValuePair(typeof (SByte), JniSByteValueMarshaler.Instance), + new KeyValuePair(typeof (SByte?), JniNullableSByteValueMarshaler.Instance), + new KeyValuePair(typeof (Char), JniCharValueMarshaler.Instance), + new KeyValuePair(typeof (Char?), JniNullableCharValueMarshaler.Instance), + new KeyValuePair(typeof (Int16), JniInt16ValueMarshaler.Instance), + new KeyValuePair(typeof (Int16?), JniNullableInt16ValueMarshaler.Instance), + new KeyValuePair(typeof (Int32), JniInt32ValueMarshaler.Instance), + new KeyValuePair(typeof (Int32?), JniNullableInt32ValueMarshaler.Instance), + new KeyValuePair(typeof (Int64), JniInt64ValueMarshaler.Instance), + new KeyValuePair(typeof (Int64?), JniNullableInt64ValueMarshaler.Instance), + new KeyValuePair(typeof (Single), JniSingleValueMarshaler.Instance), + new KeyValuePair(typeof (Single?), JniNullableSingleValueMarshaler.Instance), + new KeyValuePair(typeof (Double), JniDoubleValueMarshaler.Instance), + new KeyValuePair(typeof (Double?), JniNullableDoubleValueMarshaler.Instance), + }; + } } } @@ -226,7 +229,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -237,7 +239,6 @@ public override Type MarshalType { public override Boolean CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -299,7 +300,6 @@ sealed class JniNullableBooleanValueMarshaler : JniValueMarshaler { public override Boolean? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -370,7 +370,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -381,7 +380,6 @@ public override Type MarshalType { public override SByte CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -443,7 +441,6 @@ sealed class JniNullableSByteValueMarshaler : JniValueMarshaler { public override SByte? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -514,7 +511,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -525,7 +521,6 @@ public override Type MarshalType { public override Char CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -587,7 +582,6 @@ sealed class JniNullableCharValueMarshaler : JniValueMarshaler { public override Char? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -658,7 +652,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -669,7 +662,6 @@ public override Type MarshalType { public override Int16 CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -731,7 +723,6 @@ sealed class JniNullableInt16ValueMarshaler : JniValueMarshaler { public override Int16? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -802,7 +793,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -813,7 +803,6 @@ public override Type MarshalType { public override Int32 CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -875,7 +864,6 @@ sealed class JniNullableInt32ValueMarshaler : JniValueMarshaler { public override Int32? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -946,7 +934,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -957,7 +944,6 @@ public override Type MarshalType { public override Int64 CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1019,7 +1005,6 @@ sealed class JniNullableInt64ValueMarshaler : JniValueMarshaler { public override Int64? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1090,7 +1075,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1101,7 +1085,6 @@ public override Type MarshalType { public override Single CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1163,7 +1146,6 @@ sealed class JniNullableSingleValueMarshaler : JniValueMarshaler { public override Single? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1234,7 +1216,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1245,7 +1226,6 @@ public override Type MarshalType { public override Double CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -1307,7 +1287,6 @@ sealed class JniNullableDoubleValueMarshaler : JniValueMarshaler { public override Double? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs index ce7bcc563..661295717 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs @@ -82,8 +82,7 @@ public partial class JniTypeManager : IDisposable, ISetRuntime { internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods; - internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; - internal const DynamicallyAccessedMemberTypes MethodsConstructors = MethodsAndPrivateNested | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + internal const DynamicallyAccessedMemberTypes MethodsConstructors = Methods | Constructors; JniRuntime? runtime; bool disposed; @@ -167,7 +166,6 @@ public IEnumerable GetTypeSignatures (Type type) protected virtual IEnumerable GetTypeSignaturesCore (Type type) => []; - [return: DynamicallyAccessedMembers (MethodsConstructors)] public Type? GetType (JniTypeSignature typeSignature) { AssertValid (); @@ -189,25 +187,9 @@ public IEnumerable GetTypeSignatures (Type type) protected virtual string? GetSimpleReference (Type type) => null; protected virtual IEnumerable GetSimpleReferences (Type type) => []; - [return: DynamicallyAccessedMembers (MethodsConstructors)] protected virtual Type? GetTypeForSimpleReference (string jniSimpleReference) => null; public virtual IEnumerable GetTypes (JniTypeSignature typeSignature) => []; - public virtual IEnumerable GetReflectionConstructibleTypes (JniTypeSignature typeSignature) => []; - - public class ReflectionConstructibleType - { - public ReflectionConstructibleType ( - [DynamicallyAccessedMembers (Constructors)] - Type type) - { - Type = type; - } - - [DynamicallyAccessedMembers (Constructors)] - public Type Type { get; } - } - protected virtual IEnumerable GetTypesForSimpleReference (string jniSimpleReference) => []; static JniTypeSignature GetBuiltInTypeSignature (Type type) @@ -219,14 +201,6 @@ static JniTypeSignature GetBuiltInTypeSignature (Type type) return default; } - // IL2026/IL2111: The MethodsConstructors DAM annotation on the return type causes ILLink to analyze - // JavaProxyObject/JavaProxyThrowable/ManagedPeer's delegate-typed nested members, whose base - // constructors (Delegate.Delegate(Object,String)) are marked RequiresUnreferencedCode. - // These warnings are false positives: the delegate constructors are invoked with - // compile-time-known static method references, not via string-based reflection. - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Delegate constructors in JavaProxyObject/JavaProxyThrowable/ManagedPeer are invoked with compile-time-known method references, not via reflection.")] - [UnconditionalSuppressMessage ("Trimming", "IL2111", Justification = "Delegate constructors in JavaProxyObject/JavaProxyThrowable/ManagedPeer are invoked with compile-time-known method references, not via reflection.")] - [return: DynamicallyAccessedMembers (MethodsConstructors)] static Type? GetBuiltInType (JniTypeSignature typeSignature) { if (typeSignature.ArrayRank != 0) @@ -254,19 +228,15 @@ static JniTypeSignature GetBuiltInTypeSignature (Type type) } /// - [return: DynamicallyAccessedMembers (Constructors)] - public Type? GetInvokerType ( - [DynamicallyAccessedMembers (Constructors)] - Type type) + public Type? GetInvokerType (Type type) { if (type.IsAbstract || type.IsInterface) { return GetInvokerTypeCore (type); } return null; } - - [return: DynamicallyAccessedMembers (Constructors)] - protected virtual Type? GetInvokerTypeCore ([DynamicallyAccessedMembers (Constructors)] Type type) => null; + + protected virtual Type? GetInvokerTypeCore (Type type) => null; protected virtual IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimple) => null; @@ -306,20 +276,12 @@ static JniTypeSignature GetBuiltInTypeSignature (Type type) // Default implementation is a no-op. Derived classes (e.g. `ReflectionJniTypeManager`) // provide reflection-based registration. Override to provide custom registration. - public virtual void RegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - ReadOnlySpan methods) + public virtual void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) { } [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] - public virtual void RegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - string? methods) + public virtual void RegisterNativeMembers (JniType nativeClass, Type type, string? methods) { } } diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs index a4b199267..d9901e64d 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -42,7 +42,6 @@ partial void SetValueManager (CreationOptions options) } public abstract partial class JniValueManager : ISetRuntime, IDisposable { - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; JniRuntime? runtime; @@ -85,7 +84,7 @@ protected void EnsureNotDisposed () public abstract List GetSurfacedPeers (); public abstract void ActivatePeer ( JniObjectReference reference, - [DynamicallyAccessedMembers (Constructors)] Type type, + Type type, ConstructorInfo cinfo, object?[]? argumentValues); @@ -191,9 +190,9 @@ protected virtual bool TryUnboxPeerObject (IJavaPeerable value, [NotNullWhen (tr } public IJavaPeerable? GetPeer ( - JniObjectReference reference, - [DynamicallyAccessedMembers (Constructors)] - Type? targetType = null) + JniObjectReference reference, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) { EnsureNotDisposed (); @@ -295,7 +294,6 @@ protected virtual bool TryUnboxPeerObject (IJavaPeerable value, [NotNullWhen (tr [DynamicallyAccessedMembers (Constructors)] Type? targetType = null); - [return: DynamicallyAccessedMembers (Constructors)] internal Type? GetRuntimeType (JniObjectReference reference) { if (!reference.IsValid) @@ -309,13 +307,10 @@ protected virtual bool TryUnboxPeerObject (IJavaPeerable value, [NotNullWhen (tr public JniValueMarshaler GetValueMarshaler (Type type) => GetValueMarshalerCore (type); protected abstract JniValueMarshaler GetValueMarshalerCore (Type type); - public JniValueMarshaler GetValueMarshaler<[DynamicallyAccessedMembers (Constructors)] T> () => GetValueMarshalerCore (); - protected abstract JniValueMarshaler GetValueMarshalerCore<[DynamicallyAccessedMembers (Constructors)] T> (); + public JniValueMarshaler GetValueMarshaler () => GetValueMarshalerCore (); + protected abstract JniValueMarshaler GetValueMarshalerCore (); - internal JniObjectReference CreateLocalObjectReferenceArgument ( - [DynamicallyAccessedMembers (Constructors)] - Type type, - object? value) + internal JniObjectReference CreateLocalObjectReferenceArgument (Type type, object? value) { EnsureNotDisposed (); @@ -324,10 +319,7 @@ internal JniObjectReference CreateLocalObjectReferenceArgument ( return CreateLocalObjectReferenceArgumentCore (type, value); } - protected abstract JniObjectReference CreateLocalObjectReferenceArgumentCore ( - [DynamicallyAccessedMembers (Constructors)] - Type type, - object? value); + protected abstract JniObjectReference CreateLocalObjectReferenceArgumentCore (Type type, object? value); } } } diff --git a/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs index b98ec2843..8f8a47e3f 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs @@ -2,12 +2,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.Versioning; using System.Threading; namespace Java.Interop { @@ -200,7 +197,6 @@ static Type MakeJavaObjectArrayType (Type type) => ? arrayType ?? throw new InvalidOperationException ("Should not be reached") : typeof (JavaObjectArray<>).MakeGenericType (type); - [return: DynamicallyAccessedMembers (MethodsConstructors)] protected override Type? GetTypeForSimpleReference (string jniSimpleReference) { AssertValid (); @@ -240,13 +236,6 @@ public override IEnumerable GetTypes (JniTypeSignature typeSignature) return CreateGetTypesEnumerator (typeSignature); } - public override IEnumerable GetReflectionConstructibleTypes (JniTypeSignature typeSignature) - { - foreach (var type in GetTypes (typeSignature)) { - yield return new ReflectionConstructibleType (type); - } - } - IEnumerable CreateGetTypesEnumerator (JniTypeSignature typeSignature) { if (!typeSignature.IsValid) @@ -333,10 +322,7 @@ IEnumerable CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleRe yield break; } - [return: DynamicallyAccessedMembers (Constructors)] - protected override Type? GetInvokerTypeCore ( - [DynamicallyAccessedMembers (Constructors)] - Type type) + protected override Type? GetInvokerTypeCore (Type type) { var signature = type.GetCustomAttribute (); if (signature == null || signature.InvokerType == null) { @@ -356,20 +342,12 @@ IEnumerable CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleRe protected override ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null; - public override void RegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - ReadOnlySpan methods) + public override void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) { TryRegisterNativeMembers (nativeClass, type, methods); } - protected bool TryRegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - ReadOnlySpan methods) + protected bool TryRegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) { AssertValid (); @@ -381,21 +359,13 @@ protected bool TryRegisterNativeMembers ( } [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] - public override void RegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - string? methods) + public override void RegisterNativeMembers (JniType nativeClass, Type type, string? methods) { TryRegisterNativeMembers (nativeClass, type, methods); } [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] - protected bool TryRegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - string? methods) + protected bool TryRegisterNativeMembers (JniType nativeClass, Type type, string? methods) { AssertValid (); diff --git a/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs index 587d66911..56f836bd2 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs @@ -22,7 +22,7 @@ public abstract partial class ReflectionJniValueManager : JniValueManager { public override void ActivatePeer ( JniObjectReference reference, - [DynamicallyAccessedMembers (Constructors)] Type type, + Type type, ConstructorInfo cinfo, object?[]? argumentValues) { @@ -146,8 +146,7 @@ protected override void ConstructPeerCore (IJavaPeerable peer, ref JniObjectRefe return peer; } - [return: DynamicallyAccessedMembers (Constructors)] - static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) + static Type GetPeerType (Type type) { if (type == typeof (object)) return typeof (JavaObject); @@ -160,7 +159,6 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) IJavaPeerable? CreatePeerInstance ( ref JniObjectReference klass, - [DynamicallyAccessedMembers (Constructors)] Type targetType, ref JniObjectReference reference, JniObjectReferenceOptions transfer) @@ -194,12 +192,11 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) return TryCreatePeerInstance (ref reference, transfer, targetType); - [return: DynamicallyAccessedMembers (Constructors)] Type? GetTypeAssignableTo (JniTypeSignature sig, Type targetType) { - foreach (var t in Runtime.TypeManager.GetReflectionConstructibleTypes (sig)) { - if (targetType.IsAssignableFrom (t.Type)) { - return t.Type; + foreach (var t in Runtime.TypeManager.GetTypes (sig)) { + if (targetType.IsAssignableFrom (t)) { + return t; } } return null; @@ -209,7 +206,6 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) IJavaPeerable? TryCreatePeerInstance ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type type) { type = Runtime.TypeManager.GetInvokerType (type) ?? type; @@ -411,7 +407,7 @@ protected virtual bool TryConstructPeer ( Dictionary Marshalers = new Dictionary (); - protected override JniValueMarshaler GetValueMarshalerCore<[DynamicallyAccessedMembers (Constructors)] T> () + protected override JniValueMarshaler GetValueMarshalerCore () { EnsureNotDisposed (); @@ -472,7 +468,6 @@ protected override JniValueMarshaler GetValueMarshalerCore (Type type) } protected override JniObjectReference CreateLocalObjectReferenceArgumentCore ( - [DynamicallyAccessedMembers (Constructors)] Type type, object? value) { @@ -506,9 +501,7 @@ static JniValueMarshaler GetObjectArrayMarshaler (Type elementType) return direct (); } - static JniValueMarshaler GetObjectArrayMarshalerHelper< - [DynamicallyAccessedMembers (Constructors)] - T> () + static JniValueMarshaler GetObjectArrayMarshalerHelper () { return JavaObjectArray.Instance; } @@ -526,7 +519,6 @@ public override Type MarshalType { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { throw new NotSupportedException (); @@ -544,6 +536,7 @@ public override void DestroyArgumentState (object? value, ref JniValueMarshalerS } } + [RequiresUnreferencedCode ("Uses unconstrained reflection.")] sealed class JavaPeerableValueMarshaler : JniValueMarshaler { internal static JavaPeerableValueMarshaler Instance = new JavaPeerableValueMarshaler (); @@ -552,7 +545,6 @@ sealed class JavaPeerableValueMarshaler : JniValueMarshaler { public override IJavaPeerable? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { var jvm = JniEnvironment.Runtime; @@ -628,11 +620,7 @@ public override Expression CreateParameterToManagedExpression (JniValueMarshaler } } - sealed class DelegatingValueMarshaler< - [DynamicallyAccessedMembers (Constructors)] - T - > - : JniValueMarshaler + sealed class DelegatingValueMarshaler : JniValueMarshaler { JniValueMarshaler ValueMarshaler; @@ -646,7 +634,6 @@ public DelegatingValueMarshaler (JniValueMarshaler valueMarshaler) public override T CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return (T) ValueMarshaler.CreateValue (ref reference, options, targetType ?? typeof (T))!; @@ -683,15 +670,14 @@ public override Expression CreateReturnValueFromManagedExpression (JniValueMarsh } } + [RequiresUnreferencedCode ("Uses unconstrained reflection.")] sealed class ProxyValueMarshaler : JniValueMarshaler { - internal static ProxyValueMarshaler Instance = new ProxyValueMarshaler (); [return: MaybeNull] public override object? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { var jvm = JniEnvironment.Runtime; diff --git a/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs b/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs index 31e081590..073e8fb0b 100644 --- a/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs +++ b/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs @@ -17,7 +17,6 @@ sealed class JniStringValueMarshaler : JniValueMarshaler { public override string? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { return JniEnvironment.Strings.ToString (ref reference, options, targetType ?? typeof (string)); diff --git a/src/Java.Interop/Java.Interop/JniValueMarshaler.cs b/src/Java.Interop/Java.Interop/JniValueMarshaler.cs index 19015c6ee..f36e55ea4 100644 --- a/src/Java.Interop/Java.Interop/JniValueMarshaler.cs +++ b/src/Java.Interop/Java.Interop/JniValueMarshaler.cs @@ -119,8 +119,6 @@ public override string ToString () } public abstract class JniValueMarshaler { - - internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; internal const string ExpressionRequiresUnreferencedCode = "System.Linq.Expression usage may trim away required code."; public virtual bool IsJniValueType { @@ -135,7 +133,6 @@ public virtual Type MarshalType { public abstract object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType = null); public virtual JniValueMarshalerState CreateArgumentState (object? value, ParameterAttributes synchronize = 0) @@ -148,7 +145,6 @@ public virtual JniValueMarshalerState CreateArgumentState (object? value, internal object? CreateValue ( IntPtr handle, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { var r = new JniObjectReference (handle); @@ -233,18 +229,13 @@ protected static Expression DisposeObjectReference (Expression sourceValue) } } - public abstract class JniValueMarshaler< - [DynamicallyAccessedMembers (Constructors)] - T - > - : JniValueMarshaler + public abstract class JniValueMarshaler : JniValueMarshaler { [return: MaybeNull] public abstract T CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType = null); public virtual JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] T value, ParameterAttributes synchronize = 0) @@ -258,7 +249,6 @@ public virtual JniValueMarshalerState CreateGenericArgumentState ([MaybeNu public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType = null) { return CreateGenericValue (ref reference, options, targetType ?? typeof (T)); diff --git a/src/Java.Interop/Java.Interop/ManagedPeer.cs b/src/Java.Interop/Java.Interop/ManagedPeer.cs index 0a03e916c..b62f46964 100644 --- a/src/Java.Interop/Java.Interop/ManagedPeer.cs +++ b/src/Java.Interop/Java.Interop/ManagedPeer.cs @@ -15,6 +15,7 @@ namespace Java.Interop { [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + [RequiresUnreferencedCode ("Uses reflection to find constructors and invoke them.")] /* static */ sealed class ManagedPeer : JavaObject { internal const string JniTypeName = "net/dot/jni/ManagedPeer"; @@ -238,11 +239,6 @@ static List[] GetConstructorCandidateParameterTypes (string signature) static object?[]? GetValues (JniRuntime runtime, JniObjectReference values, ConstructorInfo cinfo) { - // https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L51-L132 - [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Constructors are preserved by the MarkJavaObjects trimmer step.")] - static object? ValueManagerGetValue (JniRuntime runtime, ref JniObjectReference value, ParameterInfo parameter) => - runtime.ValueManager.GetValue (ref value, JniObjectReferenceOptions.CopyAndDispose, parameter.ParameterType); - if (!values.IsValid) return null; @@ -254,7 +250,7 @@ static List[] GetConstructorCandidateParameterTypes (string signature) var pvalues = new object? [len]; for (int i = 0; i < len; ++i) { var n_value = JniEnvironment.Arrays.GetObjectArrayElement (values, i); - var value = ValueManagerGetValue (runtime, ref n_value, parameters [i]); + var value = runtime.ValueManager.GetValue (ref n_value, JniObjectReferenceOptions.CopyAndDispose, parameters [i].ParameterType); pvalues [i] = value; } @@ -318,7 +314,6 @@ static unsafe void RegisterNativeMembers ( } } - [return: DynamicallyAccessedMembers (ConstructorsMethodsNestedTypes)] static Type GetTypeFromSignature (JniRuntime.JniTypeManager typeManager, JniTypeSignature typeSignature, string? context = null) { return typeManager.GetType (typeSignature) ?? diff --git a/src/Java.Interop/Java.Interop/RuntimeFeature.cs b/src/Java.Interop/Java.Interop/RuntimeFeature.cs index b0ca4802a..afc27a26d 100644 --- a/src/Java.Interop/Java.Interop/RuntimeFeature.cs +++ b/src/Java.Interop/Java.Interop/RuntimeFeature.cs @@ -9,9 +9,10 @@ static class RuntimeFeature const string FeatureSwitchPrefix = "Java.Interop.RuntimeFeature."; [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedPeerNativeRegistration)}")] - internal static bool ManagedPeerNativeRegistration => + [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] + internal static bool ManagedPeerNativeRegistration { get; } = AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedPeerNativeRegistration)}", out bool isEnabled) - ? isEnabled - : ManagedPeerNativeRegistrationEnabledByDefault; + ? isEnabled + : ManagedPeerNativeRegistrationEnabledByDefault; } } diff --git a/src/Java.Interop/PublicAPI.Unshipped.txt b/src/Java.Interop/PublicAPI.Unshipped.txt index 829afc6d2..c4b727185 100644 --- a/src/Java.Interop/PublicAPI.Unshipped.txt +++ b/src/Java.Interop/PublicAPI.Unshipped.txt @@ -4,7 +4,6 @@ static Java.Interop.JniEnvironment.EndMarshalMethod(ref Java.Interop.JniTransiti virtual Java.Interop.JniRuntime.OnEnterMarshalMethod() -> void virtual Java.Interop.JniRuntime.OnUserUnhandledException(ref Java.Interop.JniTransition transition, System.Exception! e) -> void virtual Java.Interop.JniRuntime.JniTypeManager.GetInvokerTypeCore(System.Type! type) -> System.Type? -virtual Java.Interop.JniRuntime.JniTypeManager.GetReflectionConstructibleTypes(Java.Interop.JniTypeSignature typeSignature) -> System.Collections.Generic.IEnumerable! virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeForSimpleReference(string! jniSimpleReference) -> System.Type? virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeSignatureCore(System.Type! type) -> Java.Interop.JniTypeSignature virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeSignaturesCore(System.Type! type) -> System.Collections.Generic.IEnumerable! @@ -16,9 +15,6 @@ Java.Interop.JniRuntime.ReflectionJniTypeManager.ReflectionJniTypeManager() -> v Java.Interop.JniRuntime.ReflectionJniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> bool Java.Interop.JniRuntime.ReflectionJniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> bool Java.Interop.JniRuntime.JniTypeManager.GetInvokerType(System.Type! type) -> System.Type? -Java.Interop.JniRuntime.JniTypeManager.ReflectionConstructibleType -Java.Interop.JniRuntime.JniTypeManager.ReflectionConstructibleType.ReflectionConstructibleType(System.Type! type) -> void -Java.Interop.JniRuntime.JniTypeManager.ReflectionConstructibleType.Type.get -> System.Type! Java.Interop.JniRuntime.JniValueManager.GetPeer(Java.Interop.JniObjectReference reference, System.Type? targetType = null) -> Java.Interop.IJavaPeerable? Java.Interop.JniRuntime.JniValueManager.EnsureNotDisposed() -> void Java.Interop.JniRuntime.ReflectionJniValueManager @@ -107,7 +103,6 @@ override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueCore(ref J override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueMarshalerCore(System.Type! type) -> Java.Interop.JniValueMarshaler! override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueMarshalerCore() -> Java.Interop.JniValueMarshaler! override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetInvokerTypeCore(System.Type! type) -> System.Type? -override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetReflectionConstructibleTypes(Java.Interop.JniTypeSignature typeSignature) -> System.Collections.Generic.IEnumerable! override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetReplacementMethodInfoCore(string! jniSimpleReference, string! jniMethodName, string! jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetReplacementTypeCore(string! jniSimpleReference) -> string? override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetSimpleReference(System.Type! type) -> string? diff --git a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs index b6d93f71a..294d29050 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs @@ -63,7 +63,6 @@ IEnumerable CreateSimpleReferencesEnumerator (Type type) public override void RegisterNativeMembers ( JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] Type type, ReadOnlySpan methods) { From f2b767029395ed959babeff094911b4dfe73d587 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 23 Jun 2026 18:54:58 +0200 Subject: [PATCH 2/8] Update tests for DAM attribute removal Remove test-side DAM annotations that no longer match the updated runtime signatures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs | 1 - .../Java.Interop/JniValueMarshalerContractTests.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs index d1b37858e..99004f98c 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs @@ -68,7 +68,6 @@ protected override IEnumerable GetTypesForSimpleReference (string jniSimpl #pragma warning restore CS8600 } - [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] protected override Type? GetTypeForSimpleReference (string jniSimpleReference) { return base.GetTypeForSimpleReference (jniSimpleReference) ?? diff --git a/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs b/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs index 095c4467d..978e89cf8 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs @@ -664,7 +664,6 @@ public DemoValueTypeValueMarshaler () public override DemoValueType CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type targetType) { var v = Int32Marshaler.CreateGenericValue (ref reference, options, typeof (int)); From 2761dd327d77596bd2a861a90687ecb12c9e222e Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 23 Jun 2026 19:08:21 +0200 Subject: [PATCH 3/8] Address DAM removal review feedback Update the builtin marshaler template and NativeAOT sample suppression justifications after removing broad DAM annotations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../NativeAotTypeManager.cs | 2 +- .../NativeAotTypeManager.cs | 2 +- .../Java.Interop/JniBuiltinMarshalers.tt | 24 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs b/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs index 466acabbe..8cc561582 100644 --- a/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs +++ b/samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs @@ -25,7 +25,7 @@ partial class NativeAotTypeManager : JniRuntime.ReflectionJniTypeManager { ["my/MainActivity"] = typeof (MainActivity), }; - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Sample only (see class comment): this assembly is rooted via TrimmerRootAssembly and the members reflected over during registration are preserved by the [DynamicallyAccessedMembers] annotations on the RegisterNativeMembers(Type) -> FindAndCallRegisterMethod path, so trimming does not remove what reflection needs.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Sample only (see class comment): this assembly is rooted via TrimmerRootAssembly. The reflection-based registration path is not trim-clean, and this sample intentionally suppresses the warning rather than proving each reflected member to the trimmer.")] [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Sample only (see class comment): built-in member registration calls CreateDelegate on compile-time-known static methods (no MakeGenericType / expression compilation), so no runtime code generation is required.")] public NativeAotTypeManager () { diff --git a/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs b/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs index a3b3006a3..eb6703318 100644 --- a/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs +++ b/samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs @@ -16,7 +16,7 @@ namespace Hello_NativeAOTFromJNI; // moved that responsibility to callers via [RequiresDynamicCode]/[RequiresUnreferencedCode]. class NativeAotTypeManager : JniRuntime.ReflectionJniTypeManager { - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Sample only (see class comment): this assembly is rooted via TrimmerRootAssembly and the members reflected over during registration are preserved by the [DynamicallyAccessedMembers] annotations on the RegisterNativeMembers(Type) -> FindAndCallRegisterMethod path, so trimming does not remove what reflection needs.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Sample only (see class comment): this assembly is rooted via TrimmerRootAssembly. The reflection-based registration path is not trim-clean, and this sample intentionally suppresses the warning rather than proving each reflected member to the trimmer.")] [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Sample only (see class comment): built-in member registration calls CreateDelegate on compile-time-known static methods (no MakeGenericType / expression compilation), so no runtime code generation is required.")] public NativeAotTypeManager () { diff --git a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt index 3e0de6186..61d0d25cf 100644 --- a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt +++ b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt @@ -118,22 +118,25 @@ namespace Java.Interop { }; } - static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); - - static KeyValuePair[] InitJniBuiltinMarshalers () + partial class ReflectionJniValueManager { - return new []{ - new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), - new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), + static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); + + static KeyValuePair[] InitJniBuiltinMarshalers () + { + return new []{ + new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), + new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), <# foreach (var type in types) { #> - new KeyValuePair(typeof (<#= type.Type #>), Jni<#= type.Type #>ValueMarshaler.Instance), - new KeyValuePair(typeof (<#= type.Type #>?), JniNullable<#= type.Type #>ValueMarshaler.Instance), + new KeyValuePair(typeof (<#= type.Type #>), Jni<#= type.Type #>ValueMarshaler.Instance), + new KeyValuePair(typeof (<#= type.Type #>?), JniNullable<#= type.Type #>ValueMarshaler.Instance), <# } #> - }; + }; + } } } <# @@ -186,7 +189,6 @@ namespace Java.Interop { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -197,7 +199,6 @@ namespace Java.Interop { public override <#= type.Type #> CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -259,7 +260,6 @@ namespace Java.Interop { public override <#= type.Type #>? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) From 101d6f3b4fe311627fd9e8cc12ac1d564f26bed7 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 23 Jun 2026 23:32:19 +0200 Subject: [PATCH 4/8] It's not possible to switch the ManagedPeer feature switch at runtime anymore --- .../Java.Interop/JniRuntimeTest.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs index 18aed78d4..0bcfe8391 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs @@ -80,21 +80,6 @@ public void BuiltInSimpleReferenceMap_ContainsManagedPeerByDefault () Assert.IsTrue (types.Contains (typeof (ManagedPeer))); } -#if !__ANDROID__ - [Test] - public void ManagedPeerNativeRegistrationFalse_RemovesManagedPeerBuiltinMapping () - { - var c = JniRuntime.CurrentRuntime; - AppContext.SetSwitch ("Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration", false); - try { - var types = c.TypeManager.GetTypes (new JniTypeSignature (ManagedPeer.JniTypeName)); - Assert.IsEmpty (types); - } finally { - AppContext.SetSwitch ("Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration", true); - } - } -#endif // !__ANDROID__ - class JavaVMWithNullBuilder : JniRuntime { public JavaVMWithNullBuilder () : base ((JniRuntime.CreationOptions) null) From 4e0e5f8fb7a0e570c56b69848619f8632f69add2 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Jun 2026 01:01:40 +0200 Subject: [PATCH 5/8] Disable ManagedPeer in NativeAOT samples --- .../Hello-NativeAOTFromAndroid.csproj | 4 ++++ samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj index 5923127ff..c532c758a 100644 --- a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj +++ b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj @@ -21,6 +21,10 @@ true + + + + diff --git a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj index bf970f8ae..fc35ae604 100644 --- a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj +++ b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj @@ -17,6 +17,10 @@ AnyCPU + + + + From 351653be862a25cc83511ea0ebfcd3f6ab165570 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Jun 2026 08:02:43 +0200 Subject: [PATCH 6/8] Suppress ManagedPeer initialization warnigs for now --- src/Java.Interop/Java.Interop/JniRuntime.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Java.Interop/Java.Interop/JniRuntime.cs b/src/Java.Interop/Java.Interop/JniRuntime.cs index 3a68f9b46..5e4719c1e 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.cs @@ -236,6 +236,13 @@ protected JniRuntime (CreationOptions options) #if !XA_JI_EXCLUDE if (RuntimeFeature.ManagedPeerNativeRegistration) { + InitManagedPeer (); + } + + [UnconditionalSuppressMessage ("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The code is only executed when the feature is explicitly enabled.")] + static void InitManagedPeer () + { ManagedPeer.Init (); } #endif // !XA_JI_EXCLUDE From 38d719537e1acbdaf83c9fc4eb3f3b7020cae211 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Jun 2026 09:06:28 +0200 Subject: [PATCH 7/8] Enable ManagedPeer in sample again --- samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj index fc35ae604..bf970f8ae 100644 --- a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj +++ b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj @@ -17,10 +17,6 @@ AnyCPU - - - - From 181eb451dde0a38bf643a77eb64b8e8f8c84db04 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Jun 2026 10:57:46 +0200 Subject: [PATCH 8/8] Remove unnecessary modification to the sample --- .../Hello-NativeAOTFromAndroid.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj index c532c758a..5923127ff 100644 --- a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj +++ b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj @@ -21,10 +21,6 @@ true - - - -