-
Notifications
You must be signed in to change notification settings - Fork 64
[Java.Interop] Make JavaProxyObject.RegisterNativeMembers private again #1468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b5d3834
48b16f5
b2a2a15
8580bd9
9178c6f
a8f3f2b
1fcc5ec
4de18b3
40d44cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,148 +1,49 @@ | ||
| using Java.Interop; | ||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
| namespace Hello_NativeAOTFromJNI; | ||
|
|
||
| class NativeAotTypeManager : JniRuntime.JniTypeManager { | ||
| internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods; | ||
| internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; | ||
| internal const DynamicallyAccessedMemberTypes MethodsConstructors = MethodsAndPrivateNested | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; | ||
| using Java.Interop; | ||
|
|
||
| protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpleReference) | ||
| { | ||
| var target = GetTypeForSimpleReference (jniSimpleReference); | ||
| if (target != null) | ||
| yield return target; | ||
| } | ||
| namespace Hello_NativeAOTFromJNI; | ||
|
|
||
| // This sample derives from the reflection-based JniRuntime.ReflectionJniTypeManager, which is | ||
| // annotated [RequiresDynamicCode]/[RequiresUnreferencedCode], so the constructor below suppresses | ||
| // the resulting IL2026/IL3050 trim/AOT warnings. | ||
| // | ||
| // Suppressing here is intentional and good enough: these NativeAOT projects are *samples*, not | ||
| // product code. .NET for Android (what we actually ship) does not pair ReflectionJniTypeManager | ||
| // with NativeAOT, so it isn't worth the effort to make these samples fully trim/AOT-clean right now. | ||
| // The reflection paths were always trim/AOT-unsafe: before dotnet/java-interop#1441 the equivalent | ||
| // suppressions lived (buried) inside JniTypeManager itself, justified "NotUsedInAndroid"; #1441 just | ||
| // moved that responsibility to callers via [RequiresDynamicCode]/[RequiresUnreferencedCode]. | ||
| class NativeAotTypeManager : JniRuntime.ReflectionJniTypeManager { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 The safety net is also thin: Rule: Consider trimmer/NativeAOT impact
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Acknowledged — and this is a deliberate trade-off, now documented in a class-level comment ( You're right that deriving from On the CI safety net — you're correct, and I won't overclaim:
If keeping one sample on the reflection-free path is something you'd like, I'm happy to do it as a follow-up — but I'd rather not expand this PR (its job is to unblock the dotnet/android bump). |
||
|
|
||
| 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 () | ||
| { | ||
| } | ||
|
|
||
| // The base ReflectionJniTypeManager resolves built-in types (primitives, java/lang/String, | ||
| // 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) | ||
| { | ||
| return jniSimpleReference switch { | ||
| "V" => typeof (void), | ||
| "Z" => typeof (bool), | ||
| "java/lang/Boolean" => typeof (bool?), | ||
| "B" => typeof (sbyte), | ||
| "java/lang/Byte" => typeof (sbyte?), | ||
| "C" => typeof (char), | ||
| "java/lang/Character" => typeof (char?), | ||
| "S" => typeof (short), | ||
| "java/lang/Short" => typeof (short?), | ||
| "I" => typeof (int), | ||
| "java/lang/Integer" => typeof (int?), | ||
| "J" => typeof (long), | ||
| "java/lang/Long" => typeof (long?), | ||
| "F" => typeof (float), | ||
| "java/lang/Float" => typeof (float?), | ||
| "D" => typeof (double), | ||
| "java/lang/Double" => typeof (double?), | ||
| Example.ManagedType.JniTypeName => typeof (Example.ManagedType), | ||
| "java/lang/Object" => typeof (Java.Lang.Object), | ||
| "java/lang/String" => typeof (Java.Lang.String), | ||
| _ => null, | ||
| }; | ||
| } | ||
|
|
||
| public override IEnumerable<Type> GetTypes (JniTypeSignature typeSignature) | ||
| { | ||
| if (!typeSignature.IsValid || typeSignature.ArrayRank != 0 || typeSignature.SimpleReference == null) | ||
| return []; | ||
| return GetTypesForSimpleReference (typeSignature.SimpleReference); | ||
| } | ||
|
|
||
| public override IEnumerable<JniRuntime.JniTypeManager.ReflectionConstructibleType> GetReflectionConstructibleTypes (JniTypeSignature typeSignature) | ||
| { | ||
| if (!typeSignature.IsValid || typeSignature.ArrayRank != 0 || typeSignature.SimpleReference == null) | ||
| yield break; | ||
| var target = GetTypeForSimpleReference (typeSignature.SimpleReference); | ||
| if (target != null) | ||
| yield return new JniRuntime.JniTypeManager.ReflectionConstructibleType (target); | ||
| } | ||
|
|
||
| protected override IEnumerable<string> GetSimpleReferences (Type type) | ||
| { | ||
| return CreateSimpleReferencesEnumerator (type); | ||
| } | ||
|
|
||
| IEnumerable<string> CreateSimpleReferencesEnumerator (Type type) | ||
| { | ||
| if (type == typeof (Example.ManagedType)) | ||
| yield return Example.ManagedType.JniTypeName; | ||
| else if (type == typeof (Java.Lang.Object)) | ||
| yield return "java/lang/Object"; | ||
| else if (type == typeof (Java.Lang.String)) | ||
| yield return "java/lang/String"; | ||
| } | ||
|
|
||
| protected override string? GetSimpleReference (Type type) | ||
| { | ||
| return GetSimpleReferences (type).FirstOrDefault (); | ||
| if (jniSimpleReference == Example.ManagedType.JniTypeName) | ||
| return typeof (Example.ManagedType); | ||
| return base.GetTypeForSimpleReference (jniSimpleReference); | ||
| } | ||
|
|
||
| protected override JniTypeSignature GetTypeSignatureCore (Type type) | ||
| { | ||
| var simpleReference = GetSimpleReference (type); | ||
| return simpleReference == null ? default : new JniTypeSignature (simpleReference, 0, false); | ||
| } | ||
|
|
||
| protected override IEnumerable<JniTypeSignature> GetTypeSignaturesCore (Type type) | ||
| { | ||
| var signature = GetTypeSignatureCore (type); | ||
| if (signature.IsValid) | ||
| yield return signature; | ||
| } | ||
|
|
||
| [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] | ||
| protected override Type? GetInvokerTypeCore ( | ||
| [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] | ||
| Type type) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| protected override IReadOnlyList<string>? GetStaticMethodFallbackTypesCore (string jniSimpleReference) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| protected override string? GetReplacementTypeCore (string jniSimpleReference) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| protected override JniRuntime.ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSourceType, string jniMethodName, string jniMethodSignature) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public override void RegisterNativeMembers ( | ||
| JniType nativeClass, | ||
| [DynamicallyAccessedMembers (MethodsAndPrivateNested)] | ||
| Type type, | ||
| ReadOnlySpan<char> methods) | ||
| { | ||
| if (TryRegisterBuiltInNativeMembers (nativeClass, nativeClass.Name, methods)) | ||
| return; | ||
|
|
||
| if (type != typeof (Example.ManagedType)) { | ||
| if (!methods.IsEmpty) | ||
| throw new NotSupportedException ($"Could not register native members for type '{type.FullName}'."); | ||
| return; | ||
| } | ||
|
|
||
| var registrations = new List<JniNativeMethodRegistration> (); | ||
| Example.ManagedType.RegisterNativeMembers (new JniNativeMethodRegistrationArguments (registrations, null)); | ||
| if (registrations.Count > 0) | ||
| nativeClass.RegisterNativeMethods (registrations.ToArray ()); | ||
| } | ||
|
|
||
| [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan<char>)")] | ||
| public override void RegisterNativeMembers ( | ||
| JniType nativeClass, | ||
| [DynamicallyAccessedMembers (MethodsAndPrivateNested)] | ||
| Type type, | ||
| string? methods) | ||
| protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpleReference) | ||
| { | ||
| RegisterNativeMembers (nativeClass, type, methods.AsSpan ()); | ||
| if (jniSimpleReference == Example.ManagedType.JniTypeName) | ||
| yield return typeof (Example.ManagedType); | ||
| foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) | ||
| yield return t; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.