Skip to content

Commit

Permalink
[Java.Interop] Avoid Type.GetType() in ManagedPeer
Browse files Browse the repository at this point in the history
Fixes: #1165

Context: #1153
Context: #1157

When building for NativeAOT (#1153) or when building .NET Android
apps with `-p:IsAotcompatible=true` (#1157), we get [IL2057][0]
warnings from `ManagedPeer.cs`:

        ManagedPeer.cs(93,19,93,112): warning IL2057: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(String, Boolean)'. It's not possible to guarantee the availability of the target type.
        ManagedPeer.cs(156,18,156,65): warning IL2057: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(String, Boolean)'. It's not possible to guarantee the availability of the target type.
        ManagedPeer.cs(198,35,198,92): warning IL2057: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(String, Boolean)'. It's not possible to guarantee the availability of the target type.

These warnings are because `ManagedPeer.Construct()` and
`ManagedPeer.RegisterNativeMembers()` use `Type.GetType()` on string
values provided *from Java code*, and thus the IL trimmer does not
have visibility into those strings, and thus cannot reliably
determine which types need to be preserved:

	// Java Callable Wrapper
	/* partial */ class ManagedType
	{
	  public static final String __md_methods;
	  static {
	    __md_methods =
	      "n_GetString:()Ljava/lang/String;:__export__\n" +
	      "";
	    net.dot.jni.ManagedPeer.registerNativeMembers (
	        /* nativeClass */             ManagedType.class,
	        /* assemblyQualifiedName */   "Example.ManagedType, Hello-NativeAOTFromJNI",
	        /* methods */                 __md_methods);
	  }

	  public ManagedType (int p0)
	  {
	    super ();
	    if (getClass () == ManagedType.class) {
	      net.dot.jni.ManagedPeer.construct (
	          /* self */                  this,
	          /* assemblyQualifiedName */ "Example.ManagedType, Hello-NativeAOTFromJNI",
	          /* constructorSignature */  "System.Int32, System.Runtime",
	          /* arguments */             new java.lang.Object[] { p0 });
	    }
	  }
	}

`ManagedPeer.construct()` passes *two* sets of assembly-qualified
type names: `assemblyQualifiedName` contains the type to construct,
while `constructorSignature` contains a `:`-separated list of
assembly-qualified type names for the constructor parameters.
Each of these are passed to `Type.GetType()`.

`ManagedPeer.registerNativeMembers()` passes an assembly-qualified
type name to `ManagedPeer.RegisterNativeMembers()`, which passes the
assembly-qualified type name to `Type.GetType()` to find the type
to register native methods for.

If we more strongly rely on JNI signatures, we can remove the need
for Java Callable Wrappers to contain assembly-qualified type names
entirely, thus removing the need for `ManagedPeer` to use
`Type.GetType()`, removing the IL2057 warnings.

For `ManagedPeer.construct()`, `assemblyQualifiedName` can be
replaced with getting the JNI type signature from `self.getClass()`,
and `constructorSignature` can be replaced with a
*JNI method signature* of the calling constructor.

For `ManagedPeer.registerNativeMembers()`, `assemblyQualifiedName`
can be replaced with getting the JNI type signature from `nativeClass`.

	// Java Callable Wrapper
	/* partial */ class ManagedType
	{
	  public static final String __md_methods;
	  static {
	    __md_methods =
	      "n_GetString:()Ljava/lang/String;:__export__\n" +
	      "";
	    net.dot.jni.ManagedPeer.registerNativeMembers (
	        /* nativeClass */             ManagedType.class,
	        /* methods */                 __md_methods);
	  }

	  public ManagedType (int p0)
	  {
	    super ();
	    if (getClass () == ManagedType.class) {
	      net.dot.jni.ManagedPeer.construct (
	          /* self */                  this,
	          /* constructorSignature */  "(I)V",
	          /* arguments */             new java.lang.Object[] { p0 });
	    }
	  }
	}

Furthermore, if we add `[DynamicallyAccessedMembers]` to
`JniRuntime.JniTypeManager.GetType()`, we can fix some [IL2075][1]
warnings which appeared after fixing the IL2057 warnings.

Aside: Excising assembly-qualified type names from Java Callable
Wrappers had some "interesting" knock-on effects in the unit tests,
requiring that more typemap information be explicitly provided.
(This same information was *implicitly* provided before, via the
provision of assembly-qualified type names everywhere…)

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/IL2057
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/il2075
  • Loading branch information
jonpryor committed Nov 25, 2023
1 parent 8b85462 commit 0fab1d3
Show file tree
Hide file tree
Showing 20 changed files with 107 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -825,9 +825,7 @@ void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, str
case JavaPeerStyle.JavaInterop1:
sw.Write ("net.dot.jni.ManagedPeer.registerNativeMembers (");
sw.Write (self.name);
sw.Write (".class, \"");
sw.Write (managedTypeName);
sw.Write ("\", ");
sw.Write (".class, ");
sw.Write (field);
sw.WriteLine (");");
break;
Expand Down Expand Up @@ -1025,9 +1023,7 @@ void GenerateConstructor (Signature ctor, TextWriter sw)
switch (CodeGenerationTarget) {
case JavaPeerStyle.JavaInterop1:
sw.Write ("net.dot.jni.ManagedPeer.construct (this, \"");
sw.Write (type.GetPartialAssemblyQualifiedName (cache));
sw.Write ("\", \"");
sw.Write (ctor.ManagedParameters);
sw.Write (ctor.JniSignature);
sw.Write ("\", new java.lang.Object[] { ");
sw.Write (ctor.ActivateCall);
sw.WriteLine (" });");
Expand Down
4 changes: 4 additions & 0 deletions src/Java.Interop/Java.Interop/JavaProxyObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Java.Interop {

Expand Down Expand Up @@ -72,6 +73,7 @@ public override bool Equals (object? obj)
}

// TODO: Keep in sync with the code generated by ExportedMemberBuilder
[UnmanagedFunctionPointer (CallingConvention.Winapi)]
delegate bool EqualsMarshalMethod (IntPtr jnienv, IntPtr n_self, IntPtr n_value);
static bool Equals (IntPtr jnienv, IntPtr n_self, IntPtr n_value)
{
Expand All @@ -92,6 +94,7 @@ static bool Equals (IntPtr jnienv, IntPtr n_self, IntPtr n_value)
}

// TODO: Keep in sync with the code generated by ExportedMemberBuilder
[UnmanagedFunctionPointer (CallingConvention.Winapi)]
delegate int GetHashCodeMarshalMethod (IntPtr jnienv, IntPtr n_self);
static int GetHashCode (IntPtr jnienv, IntPtr n_self)
{
Expand All @@ -109,6 +112,7 @@ static int GetHashCode (IntPtr jnienv, IntPtr n_self)
}
}

[UnmanagedFunctionPointer (CallingConvention.Winapi)]
delegate IntPtr ToStringMarshalMethod (IntPtr jnienv, IntPtr n_self);
static IntPtr ToString (IntPtr jnienv, IntPtr n_self)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ static Dictionary<string, Type> InitJniBuiltinSimpleReferenceToType ()
{
return new Dictionary<string, Type> (StringComparer.Ordinal) {
{"java/lang/String", typeof (string)},
{"net/dot/jni/internal/JavaProxyObject", typeof (JavaProxyObject)},
{"net/dot/jni/internal/JavaProxyThrowable", typeof (JavaProxyThrowable)},
{"net/dot/jni/ManagedPeer", typeof (ManagedPeer)},
{"V", typeof (void)},
{"Z", typeof (Boolean)},
{"java/lang/Boolean", typeof (Boolean?)},
Expand All @@ -156,6 +159,7 @@ static KeyValuePair<Type, JniValueMarshaler>[] InitJniBuiltinMarshalers ()
{
return new []{
new KeyValuePair<Type, JniValueMarshaler>(typeof (string), JniStringValueMarshaler.Instance),
new KeyValuePair<Type, JniValueMarshaler>(typeof (JavaProxyObject), ProxyValueMarshaler.Instance),
new KeyValuePair<Type, JniValueMarshaler>(typeof (Boolean), JniBooleanValueMarshaler.Instance),
new KeyValuePair<Type, JniValueMarshaler>(typeof (Boolean?), JniNullableBooleanValueMarshaler.Instance),
new KeyValuePair<Type, JniValueMarshaler>(typeof (SByte), JniSByteValueMarshaler.Instance),
Expand Down
4 changes: 4 additions & 0 deletions src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ namespace Java.Interop {
{
return new Dictionary<string, Type> (StringComparer.Ordinal) {
{"java/lang/String", typeof (string)},
{"net/dot/jni/internal/JavaProxyObject", typeof (JavaProxyObject)},
{"net/dot/jni/internal/JavaProxyThrowable", typeof (JavaProxyThrowable)},
{"net/dot/jni/ManagedPeer", typeof (ManagedPeer)},
{"V", typeof (void)},
<#
foreach (var type in types) {
Expand All @@ -119,6 +122,7 @@ namespace Java.Interop {
{
return new []{
new KeyValuePair<Type, JniValueMarshaler>(typeof (string), JniStringValueMarshaler.Instance),
new KeyValuePair<Type, JniValueMarshaler>(typeof (JavaProxyObject), ProxyValueMarshaler.Instance),
<#
foreach (var type in types) {
#>
Expand Down
16 changes: 16 additions & 0 deletions src/Java.Interop/Java.Interop/JniMemberSignature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ public JniMemberSignature (string memberName, string memberSignature)
this.memberSignature = memberSignature;
}

internal static IEnumerable<JniTypeSignature> GetParameterTypesFromMethodSignature (string jniMethodSignature)
{
if (jniMethodSignature.Length < "()V".Length || jniMethodSignature [0] != '(' ) {
throw new ArgumentException (
$"Member signature `{jniMethodSignature}` is not a method signature. Method signatures must start with `(`.",
nameof (jniMethodSignature));
}
int index = 1;
while (index < jniMethodSignature.Length &&
jniMethodSignature [index] != ')') {
var (start, length) = ExtractType (jniMethodSignature, ref index);
var jniType = jniMethodSignature.Substring (start, length);
yield return JniTypeSignature.Parse (jniType);
}
}

public static int GetParameterCountFromMethodSignature (string jniMethodSignature)
{
if (jniMethodSignature.Length < "()V".Length || jniMethodSignature [0] != '(' ) {
Expand Down
39 changes: 35 additions & 4 deletions src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,42 @@ internal JniInstanceMethods GetConstructorsForType (Type declaringType)
if (declaringType == DeclaringType)
return this;

JniInstanceMethods? methods;

lock (SubclassConstructors) {
if (!SubclassConstructors.TryGetValue (declaringType, out var methods)) {
methods = new JniInstanceMethods (declaringType);
SubclassConstructors.Add (declaringType, methods);
}
if (SubclassConstructors.TryGetValue (declaringType, out methods))
return methods;
}
// Init outside of `lock` in case we have recursive access:
// System.ArgumentException: An item with the same key has already been added. Key: Java.Interop.JavaProxyThrowable
// at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
// at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
// at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 80
// at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 80
// at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 146
// at Java.Interop.JavaException..ctor(String message) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JavaException.cs:line 52
// at Java.Interop.JavaProxyThrowable..ctor(Exception exception) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JavaProxyThrowable.cs:line 15
// at Java.Interop.JniEnvironment.Exceptions.Throw(Exception e) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Errors.cs:line 39
// at Java.Interop.JniRuntime.RaisePendingException(Exception pendingException) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniRuntime.cs:line 444
// at Java.Interop.JniTransition.Dispose() in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniTransition.cs:line 39
// at Java.Interop.ManagedPeer.RegisterNativeMembers(IntPtr jnienv, IntPtr klass, IntPtr n_nativeClass, IntPtr n_methods) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/ManagedPeer.cs:line 195
// at Java.Interop.NativeMethods.java_interop_jnienv_find_class(IntPtr jnienv, IntPtr& thrown, String classname)
// at Java.Interop.NativeMethods.java_interop_jnienv_find_class(IntPtr jnienv, IntPtr& thrown, String classname)
// at Java.Interop.JniEnvironment.Types.TryRawFindClass(IntPtr env, String classname, IntPtr& klass, IntPtr& thrown) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 135
// at Java.Interop.JniEnvironment.Types.TryFindClass(String classname, Boolean throwOnError) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 49
// at Java.Interop.JniEnvironment.Types.FindClass(String classname) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 37
// at Java.Interop.JniType..ctor(String classname) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniType.cs:line 51
// at Java.Interop.JniPeerMembers.JniInstanceMethods..ctor(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 27
// at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 77
// at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 146
// at Java.Lang.Object..ctor() in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Base/obj/Debug-net7.0/mcw/Java.Lang.Object.cs:line 32
// at Java.BaseTests.MyIntConsumer..ctor(Action`1 action) in /Users/jon/Developer/src/xamarin/java.interop/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs:line 77
// at Java.BaseTests.JavaToManagedTests.InterfaceInvokerMethod() in /Users/jon/Developer/src/xamarin/java.interop/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs:line 26
methods = new JniInstanceMethods (declaringType);
lock (SubclassConstructors) {
if (SubclassConstructors.TryGetValue (declaringType, out var m))
return m;
SubclassConstructors.Add (declaringType, methods);
return methods;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ protected virtual IEnumerable<string> GetSimpleReferences (Type type)
static readonly Type[] EmptyTypeArray = Array.Empty<Type> ();


[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public Type? GetType (JniTypeSignature typeSignature)
{
AssertValid ();
Expand Down
37 changes: 23 additions & 14 deletions src/Java.Interop/Java.Interop/ManagedPeer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
Expand Down Expand Up @@ -47,20 +48,18 @@ public override JniPeerMembers JniPeerMembers {
get {return _members;}
}

const string ConstructSignature = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V";
const string ConstructSignature = "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V";

// TODO: Keep in sync with the code generated by ExportedMemberBuilder
delegate void ConstructMarshalMethod (IntPtr jnienv,
IntPtr klass,
IntPtr n_self,
IntPtr n_assemblyQualifiedName,
IntPtr n_constructorSignature,
IntPtr n_constructorArguments);
static void Construct (
IntPtr jnienv,
IntPtr klass,
IntPtr n_self,
IntPtr n_assemblyQualifiedName,
IntPtr n_constructorSignature,
IntPtr n_constructorArguments)
{
Expand Down Expand Up @@ -90,7 +89,9 @@ static void Construct (
return;
}

var type = Type.GetType (JniEnvironment.Strings.ToString (n_assemblyQualifiedName)!, throwOnError: true)!;
var typeSig = new JniTypeSignature (JniEnvironment.Types.GetJniTypeNameFromInstance (r_self));
var type = GetTypeFromSignature (typeMgr, typeSig);

Check failure on line 93 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop (Mac - .NET)

src/Java.Interop/Java.Interop/ManagedPeer.cs#L93

src/Java.Interop/Java.Interop/ManagedPeer.cs(93,41): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 93 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop (Mac - .NET)

src/Java.Interop/Java.Interop/ManagedPeer.cs#L93

src/Java.Interop/Java.Interop/ManagedPeer.cs(93,41): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 93 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop

src/Java.Interop/Java.Interop/ManagedPeer.cs#L93

src/Java.Interop/Java.Interop/ManagedPeer.cs(93,41): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 93 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop

src/Java.Interop/Java.Interop/ManagedPeer.cs#L93

src/Java.Interop/Java.Interop/ManagedPeer.cs(93,41): Error CS0103: The name 'typeMgr' does not exist in the current context

if (type.IsGenericTypeDefinition) {
throw new NotSupportedException (
"Constructing instances of generic types from Java is not supported, as the type parameters cannot be determined.",
Expand Down Expand Up @@ -150,10 +151,11 @@ static Type[] GetParameterTypes (string? signature)
{
if (string.IsNullOrEmpty (signature))
return Array.Empty<Type> ();
var typeNames = signature!.Split (':');
var ptypes = new Type [typeNames.Length];
for (int i = 0; i < typeNames.Length; i++)
ptypes [i] = Type.GetType (typeNames [i], throwOnError:true)!;
var ptypes = new Type [JniMemberSignature.GetParameterCountFromMethodSignature (signature)];
int i = 0;
foreach (var jniType in JniMemberSignature.GetParameterTypesFromMethodSignature (signature)) {
ptypes [i++] = GetTypeFromSignature (typeMgr, jniType, signature);

Check failure on line 157 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop (Mac - .NET)

src/Java.Interop/Java.Interop/ManagedPeer.cs#L157

src/Java.Interop/Java.Interop/ManagedPeer.cs(157,45): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 157 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop (Mac - .NET)

src/Java.Interop/Java.Interop/ManagedPeer.cs#L157

src/Java.Interop/Java.Interop/ManagedPeer.cs(157,45): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 157 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop

src/Java.Interop/Java.Interop/ManagedPeer.cs#L157

src/Java.Interop/Java.Interop/ManagedPeer.cs(157,45): Error CS0103: The name 'typeMgr' does not exist in the current context

Check failure on line 157 in src/Java.Interop/Java.Interop/ManagedPeer.cs

View check run for this annotation

Azure Pipelines / Java.Interop

src/Java.Interop/Java.Interop/ManagedPeer.cs#L157

src/Java.Interop/Java.Interop/ManagedPeer.cs(157,45): Error CS0103: The name 'typeMgr' does not exist in the current context
}
return ptypes;
}

Expand All @@ -175,31 +177,31 @@ static Type[] GetParameterTypes (string? signature)
return pvalues;
}

const string RegisterNativeMembersSignature = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)V";
const string RegisterNativeMembersSignature = "(Ljava/lang/Class;Ljava/lang/String;)V";

delegate void RegisterMarshalMethod (IntPtr jnienv,
IntPtr klass,
IntPtr n_nativeClass,
IntPtr n_assemblyQualifiedName,
IntPtr n_methods);
static unsafe void RegisterNativeMembers (
IntPtr jnienv,
IntPtr klass,
IntPtr n_nativeClass,
IntPtr n_assemblyQualifiedName,
IntPtr n_methods)
{
var envp = new JniTransition (jnienv);
try {
var r_nativeClass = new JniObjectReference (n_nativeClass);
#pragma warning disable CA2000
var nativeClass = new JniType (ref r_nativeClass, JniObjectReferenceOptions.Copy);
#pragma warning restore CA2000

var assemblyQualifiedName = JniEnvironment.Strings.ToString (new JniObjectReference (n_assemblyQualifiedName));
var type = Type.GetType (assemblyQualifiedName!, throwOnError: true)!;
var methodsRef = new JniObjectReference (n_methods);

#if NET
var typeSig = new JniTypeSignature (nativeClass.Name);
var type = GetTypeFromSignature (JniEnvironment.Runtime.TypeManager, typeSig);

#if NET
int methodsLength = JniEnvironment.Strings.GetStringLength (methodsRef);
var methodsChars = JniEnvironment.Strings.GetStringChars (methodsRef, null);
var methods = new ReadOnlySpan<char>(methodsChars, methodsLength);
Expand All @@ -223,6 +225,13 @@ static unsafe void RegisterNativeMembers (
envp.Dispose ();
}
}

[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
static Type GetTypeFromSignature (JniRuntime.JniTypeManager typeManager, JniTypeSignature typeSignature, string? context = null)
{
return typeManager.GetType (typeSignature) ??
throw new NotSupportedException ($"Could not find System.Type corresponding to Java type {typeSignature} {(context == null ? "" : "within `" + context + "`")}.");
}
}

sealed class JniLocationException : Exception {
Expand Down
2 changes: 0 additions & 2 deletions src/Java.Interop/java/net/dot/jni/ManagedPeer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ private ManagedPeer () {

public static native void registerNativeMembers (
java.lang.Class<?> nativeClass,
String assemblyQualifiedName,
String methods);

public static native void construct (
Object self,
String assemblyQualifiedName,
String constructorSignature,
Object... arguments
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
extends java.lang.Object
implements GCUserPeerable
{
static final String assemblyQualifiedName = "Java.Interop.JavaProxyObject, Java.Interop";
static {
net.dot.jni.ManagedPeer.registerNativeMembers (
JavaProxyObject.class,
assemblyQualifiedName,
"");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
extends java.lang.Error
implements GCUserPeerable
{
static final String assemblyQualifiedName = "Java.Interop.JavaProxyThrowable, Java.Interop";
static {
net.dot.jni.ManagedPeer.registerNativeMembers (
JavaProxyThrowable.class,
assemblyQualifiedName,
"");
}

Expand Down
1 change: 1 addition & 0 deletions tests/Java.Base-Tests/Java.Base/JavaVMFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static partial void CreateJavaVM ()
var c = new TestJVM (
jars: new[]{ "java.base-tests.jar" },
typeMappings: new Dictionary<string, Type> () {
["example/MyIntConsumer"] = typeof (MyIntConsumer),
["example/MyRunnable"] = typeof (MyRunnable),
[JavaInvoker.JniTypeName] = typeof (JavaInvoker),
}
Expand Down
3 changes: 3 additions & 0 deletions tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class JavaVMFixtureTypeManager : JniRuntime.JniTypeManager {
[GenericHolder<int>.JniTypeName] = typeof (GenericHolder<>),
[RenameClassBase.JniTypeName] = typeof (RenameClassBase),
[RenameClassDerived.JniTypeName] = typeof (RenameClassDerived),
[CallVirtualFromConstructorBase.JniTypeName] = typeof (CallVirtualFromConstructorBase),
[CallVirtualFromConstructorDerived.JniTypeName] = typeof (CallVirtualFromConstructorDerived),
[GetThis.JniTypeName] = typeof (GetThis),
};

public JavaVMFixtureTypeManager ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ public class CallVirtualFromConstructorDerived
extends CallVirtualFromConstructorBase
implements GCUserPeerable
{
static final String assemblyQualifiedName = "Java.InteropTests.CallVirtualFromConstructorDerived, Java.Interop-Tests";
static {
net.dot.jni.ManagedPeer.registerNativeMembers (
CallVirtualFromConstructorDerived.class,
assemblyQualifiedName,
"");
}

Expand All @@ -23,8 +21,7 @@ public CallVirtualFromConstructorDerived (int value) {
if (CallVirtualFromConstructorDerived.class == getClass ()) {
net.dot.jni.ManagedPeer.construct (
this,
assemblyQualifiedName,
"System.Int32",
"(I)V",
value
);
}
Expand Down
5 changes: 1 addition & 4 deletions tests/Java.Interop-Tests/java/net/dot/jni/test/GetThis.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

public class GetThis implements GCUserPeerable {

static final String assemblyQualifiedName = "Java.InteropTests.GetThis, Java.Interop-Tests";
static {
net.dot.jni.ManagedPeer.registerNativeMembers (
GetThis.class,
assemblyQualifiedName,
"");
}

Expand All @@ -20,8 +18,7 @@ public GetThis () {
if (GetThis.class == getClass ()) {
net.dot.jni.ManagedPeer.construct (
this,
assemblyQualifiedName,
""
"()V"
);
}
}
Expand Down
Loading

0 comments on commit 0fab1d3

Please sign in to comment.