From: https://github.com/xamarin/java.interop/issues/264
[Export] method which contains an array parameter.It works!
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
System.NotSupportedException: Only primitive types and IJavaObject is supported in array type in callback method parameter or return value
What's funny is that float[] is a "primitive type" for array types.
Is there anything I can do to help to move this issue forward?
Some of these lines fixes the array item check part of the issue. https://gist.github.com/atsushieno/a69bff3afe0afc2e7893e26af61450a1
However the changes from at https://github.com/xamarin/monodroid/commit/0d547ce broke array conversion that I have no idea how to fix. @jonpryor
Repro:
FooBar.java (AndroidJavaSource):
package androidtest1;
public class FooBar
{
public static void invokeJCW (Object instance) throws Exception
{
java.lang.reflect.Method [] methods = Class.forName("androidtest1.Example").getMethods ();
for (int i = 0; i < methods.length; i++)
if (methods [i].getName () == "SetRanges") {
Object arg = new double [] {0, 1, 2};
methods [i].invoke (instance, "foo", arg, 4);
return;
}
throw new Exception ("method does not exist");
}
}
MainActivity.cs:
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
var methods = Java.Lang.Class.ForName ("androidtest1.FooBar")
.GetMethods ();
var invoker = methods.FirstOrDefault (_ => _.Name == "invokeJCW");
invoker.Invoke (null, new Example ());
}
public class Example : Java.Lang.Object
{
[Export]
public void SetRanges (string text, double [] args, double arg2)
{
}
}
}
Ok.
FYI, cannot access this link
However the changes from at xamarin/monodroid@0d547ce broke array conversion
Seems like not too many people need this feature?
Sorry it is a private repo that only makes sense to the devs.
@atsushieno: I don't immediately see how or why that commit broke things. Before the change, DynamicInvokeTypeInfo.jnienv_newarray was a MethodInfo to JNIEnv.NewArray<T>(T[]), and should have been a generic method definition.
After the change, DynamicInvokeTypeInfo.jnienv_newarray is a MethodInfo to JNIEnv.NewArray<T>(T[]), and is a generic method definition.
In System.Array terms:
// Actually the `csharp` command, but close enough...
// Ways to obtain the MethodInfo for System.Array.BinarySearch<T>(T[], int)
var a = typeof(Array);
// 1. Via Reflection + LINQ
var bsr = a.GetMethods().First(m => m.IsGenericMethod && m.Name == "BinarySearch" && m.GetParameters().Length == 2);
// 2: Via Delegate conversion + Delegate.Method
public class E {
public static MethodInfo GetBinarySearchT<T>(Func<T[], T, int> func) {
return func.Method.GetGenericMethodDefinition ();
}
}
var bsm = E.GetBinarySearchT<int>(Array.BinarySearch);
// Results are the same, but mechanism 2 is much faster.
Console.WriteLine(bsm == bsr);
// true
The change, that you are quite aware of, therefore results in:
[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Call to method AndroidTest1.Example.SetRanges: Parameter 1. Can't cast from T[] to System.Double[]
[MonoDroid] at Mono.CodeGeneration.CodeGenerationHelper.GenerateMethodCall (System.Reflection.Emit.ILGenerator gen, Mono.CodeGeneration.CodeExpression target, System.Reflection.MethodBase method, System.Type[] parameterTypes, Mono.CodeGeneration.CodeExpression[] parameters) [0x00118] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeGenerationHelper.GenerateMethodCall (System.Reflection.Emit.ILGenerator gen, Mono.CodeGeneration.CodeExpression target, System.Reflection.MethodBase method, Mono.CodeGeneration.CodeExpression[] parameters) [0x00041] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeMethodCall.Generate (System.Reflection.Emit.ILGenerator gen) [0x00029] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeMethodCall.GenerateAsStatement (System.Reflection.Emit.ILGenerator gen) [0x00001] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeBlock.Generate (System.Reflection.Emit.ILGenerator gen) [0x0002a] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeBuilder.Generate (System.Reflection.Emit.ILGenerator gen) [0x00001] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Mono.CodeGeneration.CodeMethod.Generate (System.Reflection.Emit.ILGenerator gen) [0x00015] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Java.Interop.DynamicCallbackCodeGenerator.GenerateNativeCallbackDelegate () [0x000d3] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Java.Interop.DynamicCallbackCodeGenerator.GetCallback () [0x0000e] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at Java.Interop.DynamicCallbackCodeGenerator.Create (System.Reflection.MethodInfo method) [0x00007] in <19387e49dc8946eda9d7ad05203f74fb>:0
[MonoDroid] at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
[MonoDroid] at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <316413990ea1468fadc4a3d4de9c4235>:0
@atsushieno: From what I can tell, the change should have had no semantic effect: before the change, DynamicInvokeTypeInfo.jnienv_newarray is a MethodInfo referring to the generic method definition for JNIEnv.NewArray<T>(T[]), and after the change it continues to be a MethodInfo referring to the generic method definition for JNIEnv.NewArray<T>(T[]).
I do not believe that the commit you're referring to is responsible for the System.InvalidOperationException. "Locally reverting" that patch should show that it has nothing to do with the InvalidOperationException, and would take ~5 minutes to verify. I cannot see why it would have anything to do with the problem.
Furthermore, the only quick places I can find use of CallbackCode.jnienv_newarray is in CallbackCode.cs, e.g. within DynamicInvokeTypeInfo.ToNative(). This location uses jnienv_newarray.MakeGenericMethod(), so the created CodeMethodCall() shouldn't even be using a type parameter, it should be using a known type such as double.
Additionally, if DynamicInvokeTypeInfo.jnienv_newarray weren't a generic method definition, then the .MakeGenericMethod() call would itself have been throwing. It isn't.
Finally, I'm assuming you have a local patch to even be generating the above stack trace. What is that patch? Without any changes, we should be getting the originally mentioned NotSupportedException.
My stacktrace is based on the local patch I posted at https://github.com/xamarin/xamarin-android/issues/1259#issuecomment-368956613 . The patch also tells that there were method signature changes in JNIEnv GetArray() that resulted in method argument count mismatch. Therefore I noticed that there were incompatible API changes.
Currently md-addins broke debugger which makes it quite annoying to debug any issues.
Is there currently a workaround I could use regarding this?
No. I would completely avoid depending on any code that requires [Export] by writing managed code that overrides existing Java methods which would result in a working Java callable wrappers though.
Ok, thanks for the idea. Though I'm not sure this can work in my use case: C code calling JNI exposed code (which I intended to generate through [Export] attributes). There is no existing Java code per se.
I will look for another way.
For any native (C) functions P/Invoke just works.
That's not it, maybe I was not clear.
I'm not calling C from C# (in this case), C is calling me through JNI with https://github.com/videolan/vlc/blob/a16a24bce5e7e8fa6b2c05e63f5524e1d8df0640/modules/video_output/android/utils.c#L434
I guess my best bet then is to build the relevant java code into a .jar and put that in an Android binding library project. Thanks though.
Same issue here when trying to export the following method:
[JavascriptInterface]
[Export("log")]
public void Log(params string[] data)
{
System.Diagnostics.Debug.WriteLine("NetworkView: " + string.Join(" ", data));
}
Is this a regression? If so, could someone please point me where to find what version of Xamarin does not have this issue. Thanks.
Is there any updates regrading this issue?
Most helpful comment
Is there any updates regrading this issue?