diff --git a/src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs b/src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs index ed3f44a2e..8b8c7d0f6 100644 --- a/src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs +++ b/src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs @@ -1,3 +1,4 @@ +#nullable enable using System; namespace Java.Interop { diff --git a/src/Java.Interop.Export/Java.Interop/JavaCallableConstructorAttribute.cs b/src/Java.Interop.Export/Java.Interop/JavaCallableConstructorAttribute.cs new file mode 100644 index 000000000..23370d4cb --- /dev/null +++ b/src/Java.Interop.Export/Java.Interop/JavaCallableConstructorAttribute.cs @@ -0,0 +1,16 @@ +#nullable enable +using System; + +namespace Java.Interop { + + [AttributeUsage (AttributeTargets.Constructor, AllowMultiple=false)] + public sealed class JavaCallableConstructorAttribute : Attribute { + + public JavaCallableConstructorAttribute () + { + } + + public string? SuperConstructorExpression {get; set;} + public string? Signature {get; set;} + } +} diff --git a/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs b/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs index b4a97c94d..6b3e4458b 100644 --- a/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs +++ b/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs @@ -68,7 +68,7 @@ public JniNativeMethodRegistration CreateMarshalToManagedMethodRegistration (Jav string GetJniMethodName (JavaCallableAttribute export, MethodInfo method) { - return export.Name ?? "n_" + method.Name; + return "n_" + method.Name; } public string GetJniMethodSignature (JavaCallableAttribute export, MethodInfo method) diff --git a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs index d136f86f3..e66289184 100644 --- a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs +++ b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq.Expressions; +using System.Runtime.InteropServices; using System.Text; using Java.Interop; @@ -58,7 +59,7 @@ static MethodDefinition CreateMethodDefinition (AssemblyDefinition declaringAsse return mmDef; } - public MethodDefinition CreateRegistrationMethod (IList methods) + public void AddRegistrationMethod (TypeDefinition declaringType, IList methods) { var registrations = new MethodDefinition ( name: "__RegisterNativeMembers", @@ -70,6 +71,8 @@ public MethodDefinition CreateRegistrationMethod (IList r.Name == "System.Runtime"); - var privateCorelibRef = module.AssemblyReferences.FirstOrDefault (r => r.Name == "System.Private.CoreLib"); - - if (systemRuntimeRef == null && privateCorelibRef != null) { - systemRuntimeRef = GetSystemRuntimeReference (); - module.AssemblyReferences.Add (systemRuntimeRef); - } var selfRef = module.AssemblyReferences.FirstOrDefault (r => r.Name == newAsm.Name.Name); foreach (var member in module.GetMemberReferences ()) { Logger (TraceLevel.Verbose, $"# jonp: looking at ref for member: [{member.DeclaringType.Scope?.Name}]{member}"); - if (member.DeclaringType.Scope == privateCorelibRef) { - Logger (TraceLevel.Verbose, $"# jonp: Fixing scope ref for member: {member}"); - member.DeclaringType.Scope = systemRuntimeRef; - continue; - } if (member.DeclaringType.Scope == selfRef) { Logger (TraceLevel.Verbose, $"# jonp: Fixing scope self ref for member: {member}"); member.DeclaringType.Scope = null; @@ -261,18 +258,12 @@ public void Write (string path) } foreach (var type in module.GetTypeReferences ()) { Logger (TraceLevel.Verbose, $"# jonp: looking at ref for type: [{type.Scope}]{type}"); - if (type.Scope == privateCorelibRef) { - Logger (TraceLevel.Verbose, $"# jonp: Fixing scope ref for type: {type}"); - type.Scope = systemRuntimeRef; - continue; - } if (type.Scope == selfRef) { Logger (TraceLevel.Verbose, $"# jonp: Fixing scope self ref for type: {type}"); type.Scope = null; continue; } } - module.AssemblyReferences.Remove (privateCorelibRef); if (selfRef != null) { module.AssemblyReferences.Remove (selfRef); } diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs index 76f2bfc04..636549252 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs @@ -164,7 +164,13 @@ void AddNestedTypes (TypeDefinition type) var baseRegisteredMethod = GetBaseRegisteredMethod (minfo); if (baseRegisteredMethod != null) AddMethod (baseRegisteredMethod, minfo); - else if (minfo.AnyCustomAttributes (typeof(ExportFieldAttribute))) { + else if (minfo.AnyCustomAttributes ("Java.Interop.JavaCallableAttribute")) { + AddMethod (null, minfo); + HasExport = true; + } else if (minfo.AnyCustomAttributes ("Java.Interop.JavaCallableConstructorAttribute")) { + AddMethod (null, minfo); + HasExport = true; + } else if (minfo.AnyCustomAttributes (typeof(ExportFieldAttribute))) { AddMethod (null, minfo); HasExport = true; } else if (minfo.AnyCustomAttributes (typeof (ExportAttribute))) { @@ -295,7 +301,7 @@ void AddConstructor (MethodDefinition ctor, TypeDefinition type, string? outerTy if (!string.IsNullOrEmpty (eattr.Name)) { // Diagnostic.Warning (log, "Use of ExportAttribute.Name property is invalid on constructors"); } - ctors.Add (new Signature (ctor, eattr, cache)); + ctors.Add (new Signature (ctor, eattr, managedParameters, cache)); curCtors.Add (ctor); return; } @@ -412,6 +418,25 @@ ExportAttribute ToExportAttribute (CustomAttribute attr, IMemberDefinition decla return new ExportAttribute (name) {ThrownNames = thrown, SuperArgumentsString = superArgs}; } + ExportAttribute ToExportAttributeFromJavaCallableAttribute (CustomAttribute attr, IMemberDefinition declaringMember) + { + var name = attr.ConstructorArguments.Count > 0 + ? (string) attr.ConstructorArguments [0].Value + : declaringMember.Name; + return new ExportAttribute (name); + } + + ExportAttribute ToExportAttributeFromJavaCallableConstructorAttribute (CustomAttribute attr, IMemberDefinition declaringMember) + { + var superArgs = (string) attr.Properties + .FirstOrDefault (p => p.Name == "SuperConstructorExpression") + .Argument + .Value; + return new ExportAttribute (".ctor") { + SuperArgumentsString = superArgs, + }; + } + internal static ExportFieldAttribute ToExportFieldAttribute (CustomAttribute attr) { return new ExportFieldAttribute ((string) attr.ConstructorArguments [0].Value); @@ -447,7 +472,11 @@ static IEnumerable GetMethodRegistrationAttributes (Mono.Ceci IEnumerable GetExportAttributes (IMemberDefinition p) { - return GetAttributes (p, a => ToExportAttribute (a, p)); + return GetAttributes (p, a => ToExportAttribute (a, p)) + .Concat (GetAttributes (p, "Java.Interop.JavaCallableAttribute", + a => ToExportAttributeFromJavaCallableAttribute (a, p))) + .Concat (GetAttributes (p, "Java.Interop.JavaCallableConstructorAttribute", + a => ToExportAttributeFromJavaCallableConstructorAttribute (a, p))); } static IEnumerable GetExportFieldAttributes (Mono.Cecil.ICustomAttributeProvider p) @@ -458,7 +487,13 @@ static IEnumerable GetExportFieldAttributes (Mono.Cecil.IC static IEnumerable GetAttributes (Mono.Cecil.ICustomAttributeProvider p, Func selector) where TAttribute : class { - return p.GetCustomAttributes (typeof (TAttribute)) + return GetAttributes (p, typeof (TAttribute).FullName, selector); + } + + static IEnumerable GetAttributes (Mono.Cecil.ICustomAttributeProvider p, string attributeName, Func selector) + where TAttribute : class + { + return p.GetCustomAttributes (attributeName) .Select (selector) .Where (v => v != null) .Select (v => v!); @@ -481,7 +516,7 @@ void AddMethod (MethodDefinition? registeredMethod, MethodDefinition implemented if (type.HasGenericParameters) Diagnostic.Error (4206, LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4206); - var msig = new Signature (implementedMethod, attr, cache); + var msig = new Signature (implementedMethod, attr, managedParameters: null, cache: cache); if (!string.IsNullOrEmpty (attr.SuperArgumentsString)) { // Diagnostic.Warning (log, "Use of ExportAttribute.SuperArgumentsString property is invalid on methods"); } @@ -834,7 +869,7 @@ public Signature (MethodDefinition method, RegisterAttribute register, string? m IsDynamicallyRegistered = shouldBeDynamicallyRegistered; } - public Signature (MethodDefinition method, ExportAttribute export, IMetadataResolver cache) + public Signature (MethodDefinition method, ExportAttribute export, string? managedParameters, IMetadataResolver cache) : this (method.Name, GetJniSignature (method, cache), "__export__", null, null, export.SuperArgumentsString) { IsExport = true; @@ -842,6 +877,7 @@ public Signature (MethodDefinition method, ExportAttribute export, IMetadataReso JavaAccess = JavaCallableWrapperGenerator.GetJavaAccess (method.Attributes & MethodAttributes.MemberAccessMask); ThrownTypeNames = export.ThrownNames; JavaNameOverride = export.Name; + ManagedParameters = managedParameters; Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes, cache); } diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs index 535db5c64..e87e9b129 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs @@ -412,11 +412,17 @@ protected bool TryRegisterNativeMembers (JniType nativeClass, Type type, string? bool TryLoadJniMarshalMethods (JniType nativeClass, Type type, string? methods) { var marshalType = type?.GetNestedType ("__<$>_jni_marshal_methods", BindingFlags.NonPublic); - if (marshalType == null) + if (marshalType == null) { return false; + } - var registerMethod = marshalType.GetRuntimeMethod ("__RegisterNativeMembers", registerMethodParameters); - + var registerMethod = marshalType.GetMethod ( + name: "__RegisterNativeMembers", + bindingAttr: BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, + binder: null, + callConvention: default, + types: registerMethodParameters, + modifiers: null); return TryRegisterNativeMembers (nativeClass, marshalType, methods, registerMethod); } @@ -466,8 +472,10 @@ bool FindAndCallRegisterMethod (Type marshalType, JniNativeMethodRegistrationArg continue; } + var declaringTypeName = methodInfo.DeclaringType?.FullName ?? ""; + if ((methodInfo.Attributes & MethodAttributes.Static) != MethodAttributes.Static) { - throw new InvalidOperationException ($"The method {methodInfo} marked with {nameof (JniAddNativeMethodRegistrationAttribute)} must be static"); + throw new InvalidOperationException ($"The method `{declaringTypeName}.{methodInfo}` marked with [{nameof (JniAddNativeMethodRegistrationAttribute)}] must be static!"); } var register = (Action)methodInfo.CreateDelegate (typeof (Action)); diff --git a/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs b/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs index 4b5b6d8d9..a44b677e5 100644 --- a/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs +++ b/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs @@ -11,7 +11,9 @@ public sealed class JniTypeSignatureAttribute : Attribute { public JniTypeSignatureAttribute (string simpleReference) { +#if !JCW_ONLY_TYPE_NAMES JniRuntime.JniTypeManager.AssertSimpleReference (simpleReference, nameof (simpleReference)); +#endif // !JCW_ONLY_TYPE_NAMES SimpleReference = simpleReference; } diff --git a/src/Java.Interop/Java.Interop/ManagedPeer.cs b/src/Java.Interop/Java.Interop/ManagedPeer.cs index eb43a9e85..fa994980c 100644 --- a/src/Java.Interop/Java.Interop/ManagedPeer.cs +++ b/src/Java.Interop/Java.Interop/ManagedPeer.cs @@ -216,7 +216,7 @@ static unsafe void RegisterNativeMembers ( } catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { - Debug.WriteLine (e.ToString ()); + Debug.WriteLine ($"Exception when trying to register native methods with JNI: {e}"); envp.SetPendingException (e); } finally { diff --git a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs index 7f3e0763c..358d009c8 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs @@ -52,6 +52,10 @@ public override void RegisterNativeMembers (JniType nativeClass, Type type, Read registrations.Add (new JniNativeMethodRegistration (name, signature, marshaler!)); } + foreach (var registration in Runtime.MarshalMemberBuilder.GetExportedMemberRegistrations (type)) { + registrations.Add (registration); + } + nativeClass.RegisterNativeMethods (registrations.ToArray ()); } diff --git a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj index 4653b1065..62edf36f6 100644 --- a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj +++ b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj @@ -22,19 +22,16 @@ + - + - - - - - + diff --git a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets new file mode 100644 index 000000000..b5eae7d58 --- /dev/null +++ b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets @@ -0,0 +1,53 @@ + + + + + + + + <_RefAsmDirs Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" /> + + + <_JcwGen>"$(UtilityOutputFullPath)/jcw-gen.dll" + <_Target>--codegen-target JavaInterop1 + <_Output>-o "$(IntermediateOutputPath)/java" + <_Libpath>@(_RefAsmDirs->'-L "%(Identity)"', ' ') + + + + + + + + + <_JcwSource Include="$(IntermediateOutputPath)java\**\*.java" /> + + + <_Source Include="@(_JcwSource->Replace('%5c', '/'))" /> + <_Source Include="@(JavaExportTestJar->Replace('%5c', '/'))" /> + + + + <_JavacOpt Include="$(_JavacSourceOptions)" /> + <_JavacOpt Include="-d "$(IntermediateOutputPath)et-classes" " /> + <_JavacOpt Include="-classpath "$(OutputPath)java-interop.jar" " /> + <_JavacOpt Include=""@$(IntermediateOutputPath)_java_sources.txt"" /> + <_JavacOpt Include="-h "$(IntermediateOutputPath)et-classes" " /> + + + + + + + diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs new file mode 100644 index 000000000..4b6362dfc --- /dev/null +++ b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs @@ -0,0 +1,23 @@ +using Java.Interop; + +namespace Java.InteropTests; + +[JniTypeSignature (TypeSignature)] +class JavaCallableExample : Java.Lang.Object { + + internal const string TypeSignature = "net/dot/jni/test/JavaCallableExample"; + + [JavaCallableConstructor(SuperConstructorExpression="")] + public JavaCallableExample (int a) + { + this.a = a; + } + + int a; + + [JavaCallable ("getA")] + public int GetA () + { + return a; + } +} diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs new file mode 100644 index 000000000..c0c49a49f --- /dev/null +++ b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs @@ -0,0 +1,21 @@ +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests; + +[TestFixture] +class JavaCallableExampleTest : JavaVMFixture +{ + [Test] + public void JavaCallableWrappers () + { + using var jce = CreateUseJavaCallableExampleType (); + var m = jce.GetStaticMethod ("test", "()Z"); + var z = JniEnvironment.StaticMethods.CallStaticBooleanMethod (jce.PeerReference, m); + Assert.IsTrue (z); + } + + static JniType CreateUseJavaCallableExampleType () => + new JniType ("net/dot/jni/test/UseJavaCallableExample"); +} diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs b/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs index f28d82268..2fe03fc0d 100644 --- a/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs +++ b/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs @@ -24,10 +24,10 @@ public void AddExportMethods () .ToList (); Assert.AreEqual (11, methods.Count); - Assert.AreEqual ("action", methods [0].Name); - Assert.AreEqual ("()V", methods [0].Signature); + Assert.AreEqual ("n_InstanceAction", methods [0].Name); + Assert.AreEqual ("()V", methods [0].Signature); - Assert.AreEqual ("staticAction", methods [1].Name); + Assert.AreEqual ("n_StaticAction", methods [1].Name); Assert.AreEqual ("()V", methods [1].Signature); #if NET diff --git a/tests/Java.Interop.Export-Tests/java/com/xamarin/interop/export/ExportType.java b/tests/Java.Interop.Export-Tests/java/com/xamarin/interop/export/ExportType.java index 8e549580c..609be683e 100644 --- a/tests/Java.Interop.Export-Tests/java/com/xamarin/interop/export/ExportType.java +++ b/tests/Java.Interop.Export-Tests/java/com/xamarin/interop/export/ExportType.java @@ -25,12 +25,54 @@ public static void testStaticMethods () { throw new Error ("staticFuncMyEnum_MyEnum should return 42!"); } - public static native void staticAction (); - public static native void staticActionIJavaObject (Object test); - public static native void staticActionInt32String (int i, String s); - public static native int staticFuncMyLegacyColorMyColor_MyColor (int color1, int color2); + public static void staticAction () {n_StaticAction ();} + private static native void n_StaticAction (); - public static native boolean staticFuncThisMethodTakesLotsOfParameters ( + public static void staticActionIJavaObject (Object test) {n_StaticActionIJavaObject(test);} + private static native void n_StaticActionIJavaObject (Object test); + + public static void staticActionInt32String (int i, String s) {n_StaticActionInt32String (i, s);} + private static native void n_StaticActionInt32String (int i, String s); + + public static int staticFuncMyLegacyColorMyColor_MyColor (int color1, int color2) {return n_StaticFuncMyLegacyColorMyColor_MyColor (color1, color2);} + private static native int n_StaticFuncMyLegacyColorMyColor_MyColor (int color1, int color2); + + public static boolean staticFuncThisMethodTakesLotsOfParameters ( + boolean a, + byte b, + char c, + short d, + int e, + long f, + float g, + double h, + Object i, + String j, + ArrayList k, + String l, + Object m, + double n, + float o, + long p) { + return n_StaticFuncThisMethodTakesLotsOfParameters ( + a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m, + n, + o, + p); + } + private static native boolean n_StaticFuncThisMethodTakesLotsOfParameters ( boolean a, byte b, char c, @@ -86,12 +128,23 @@ public void testMethods () { throw new Error ("staticFuncThisMethodTakesLotsOfParameters should return true!"); } - public native void action (); - public native void actionIJavaObject (Object test); - public native long funcInt64 (); - public native Object funcIJavaObject (); - public native void staticActionInt (int i); - public native void staticActionFloat (float f); + public void action () {n_InstanceAction ();} + private native void n_InstanceAction (); + + public void actionIJavaObject (Object test) {n_InstanceActionIJavaObject (test);} + private native void n_InstanceActionIJavaObject (Object test); + + public long funcInt64 () {return n_FuncInt64 ();} + private native long n_FuncInt64 (); + + public Object funcIJavaObject () {return n_FuncIJavaObject ();} + private native Object n_FuncIJavaObject (); + + public void staticActionInt (int i) {n_StaticActionInt (i);} + private native void n_StaticActionInt (int i); + + public void staticActionFloat (float f) {n_StaticActionFloat (f);} + private native void n_StaticActionFloat (float f); ArrayList managedReferences = new ArrayList(); diff --git a/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java b/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java new file mode 100644 index 000000000..780daf4c8 --- /dev/null +++ b/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java @@ -0,0 +1,11 @@ +package net.dot.jni.test; + +import net.dot.jni.test.JavaCallableExample; + +public class UseJavaCallableExample { + + public static boolean test() { + JavaCallableExample e = new JavaCallableExample(42); + return e.getA() == 42; + } +} diff --git a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj index 1a4cea112..fc245d4d6 100644 --- a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj +++ b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj @@ -4,6 +4,7 @@ $(DotNetTargetFramework) false $(DefineConstants);HAVE_CECIL;JCW_ONLY_TYPE_NAMES + $(NoWarn);CA1019;CA1813 @@ -29,4 +30,10 @@ + + + + + + diff --git a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs index fa846a723..45adf68e5 100644 --- a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs +++ b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs @@ -102,13 +102,14 @@ public void monodroidClearReferences () Assert.AreEqual (expected, actual); } - static string Generate (Type type, string applicationJavaClass = null, string monoRuntimeInit = null) + static string Generate (Type type, string applicationJavaClass = null, string monoRuntimeInit = null, JavaPeerStyle style = JavaPeerStyle.XAJavaInterop1) { var td = SupportDeclarations.GetTypeDefinition (type); var g = new JavaCallableWrapperGenerator (td, log: null, cache: null) { ApplicationJavaClass = applicationJavaClass, GenerateOnCreateOverrides = true, MonoRuntimeInitialization = monoRuntimeInit, + CodeGenerationTarget = style, }; var o = new StringWriter (); var dir = Path.GetDirectoryName (typeof (JavaCallableWrapperGeneratorTests).Assembly.Location); @@ -449,7 +450,7 @@ public ExportsConstructors (int p0) { super (p0); if (getClass () == ExportsConstructors.class) { - mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", """", this, new java.lang.Object[] { p0 }); + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.Int32, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); } } @@ -505,7 +506,7 @@ public ExportsThrowsConstructors (int p0) throws java.lang.Throwable { super (p0); if (getClass () == ExportsThrowsConstructors.class) { - mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", """", this, new java.lang.Object[] { p0 }); + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.Int32, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); } } @@ -514,7 +515,7 @@ public ExportsThrowsConstructors (java.lang.String p0) { super (p0); if (getClass () == ExportsThrowsConstructors.class) { - mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", """", this, new java.lang.Object[] { p0 }); + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.String, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); } } @@ -618,6 +619,62 @@ public void monodroidClearReferences () refList.clear (); }} }} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateJavaInteropExample () + { + var actual = Generate (typeof (JavaInteropExample), style: JavaPeerStyle.JavaInterop1); + var expected = @"package register; + + +public class JavaInteropExample + extends java.lang.Object + implements + com.xamarin.java_interop.GCUserPeerable +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + ""n_Example:()V:__export__\n"" + + """"; + com.xamarin.java_interop.ManagedPeer.registerNativeMembers (JavaInteropExample.class, ""Xamarin.Android.ToolsTests.JavaInteropExample, Java.Interop.Tools.JavaCallableWrappers-Tests"", __md_methods); + } + + + public JavaInteropExample (int p0, int p1) + { + super (); + if (getClass () == JavaInteropExample.class) { + com.xamarin.java_interop.ManagedPeer.construct (this, ""Xamarin.Android.ToolsTests.JavaInteropExample, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.Int32, System.Private.CoreLib:System.Int32, System.Private.CoreLib"", new java.lang.Object[] { p0, p1 }); + } + } + + + public void example () + { + n_Example (); + } + + private native void n_Example (); + + private java.util.ArrayList refList; + public void jiAddManagedReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void jiClearManagedReferences () + { + if (refList != null) + refList.clear (); + } +} "; Assert.AreEqual (expected, actual); } diff --git a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs index de99b77ec..0a56b225c 100644 --- a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs +++ b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs @@ -323,4 +323,15 @@ public ExportsThrowsConstructors (int value) { } [Export (Throws = new Type [0])] public ExportsThrowsConstructors (string value) { } } + + [JniTypeSignature ("register/JavaInteropExample")] + class JavaInteropExample : Java.Lang.Object { + + + [JavaCallableConstructor(SuperConstructorExpression="")] + public JavaInteropExample (int a, int b) {} + + [JavaCallable ("example")] + public void Example () {} + } } diff --git a/tools/jnimarshalmethod-gen/App.cs b/tools/jnimarshalmethod-gen/App.cs index adf938648..fc43233c8 100644 --- a/tools/jnimarshalmethod-gen/App.cs +++ b/tools/jnimarshalmethod-gen/App.cs @@ -228,8 +228,9 @@ void ProcessAssemblies (List assemblies) // loadContext = CreateLoadContext (); AppDomain.CurrentDomain.AssemblyResolve += (o, e) => { Log (TraceLevel.Verbose, $"# jonp: resolving assembly: {e.Name}"); + var name = new AssemblyName (e.Name); foreach (var d in resolver.SearchDirectories) { - var a = Path.Combine (d, e.Name); + var a = Path.Combine (d, name.Name); var f = a + ".dll"; if (File.Exists (f)) { return Assembly.LoadFile (Path.GetFullPath (f)); @@ -549,27 +550,21 @@ void CreateMarshalMethodAssembly (string path) Log (TraceLevel.Verbose, $"## Dumping contents of marshal method for `{td.FullName}::{method.Name}({string.Join (", ", method.GetParameters ().Select (p => p.ParameterType))})`:"); Console.WriteLine (lambda.ToCSharpCode ()); #endif // _DUMP_REGISTER_NATIVE_MEMBERS + name = export?.Name ?? method.Name; + var mmDef = assemblyBuilder.Compile (lambda); - mmDef.Name = export?.Name ?? ("n_TODO" + lambda.GetHashCode ()); + mmDef.Name = name; mmTypeDef.Methods.Add (mmDef); - if (export != null) { - name = export.Name; - signature = export.Signature; - } - - if (signature == null) { - signature = builder.GetJniMethodSignature (method); - } + signature = export?.Signature ?? builder.GetJniMethodSignature (method); - registrations.Add (new ExpressionMethodRegistration (name, signature, mmDef)); + registrations.Add (new ExpressionMethodRegistration ("n_" + method.Name, signature, mmDef)); addedMethods.Add (methodName); } if (registrations.Count > 0) { - var m = assemblyBuilder.CreateRegistrationMethod (registrations); - mmTypeDef.Methods.Add (m); td.NestedTypes.Add (mmTypeDef); + assemblyBuilder.AddRegistrationMethod (mmTypeDef, registrations); } }