diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
index d27920a58..9ce77fbe3 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
@@ -66,6 +66,18 @@ JniMethodInfo GetMethodInfo (string method, string signature)
return Members.JniPeerType.GetStaticMethod (method, signature);
}
+#pragma warning disable CA1801
+ JniType GetMethodDeclaringType (JniMethodInfo method)
+ {
+#if NET
+ if (method.StaticRedirect != null) {
+ return method.StaticRedirect;
+ }
+#endif // NET
+ return Members.JniPeerType;
+ }
+#pragma warning restore CA1801
+
#if NET
JniMethodInfo? FindInFallbackTypes (string method, string signature)
{
@@ -80,6 +92,8 @@ JniMethodInfo GetMethodInfo (string method, string signature)
continue;
}
if (t.TryGetStaticMethod (method, signature, out var m)) {
+ m.StaticRedirect = t;
+ t = null;
return m;
}
}
@@ -94,61 +108,61 @@ JniMethodInfo GetMethodInfo (string method, string signature)
public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- JniEnvironment.StaticMethods.CallStaticVoidMethod (Members.JniPeerType.PeerReference, m, parameters);
+ JniEnvironment.StaticMethods.CallStaticVoidMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe bool InvokeBooleanMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticBooleanMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticBooleanMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe sbyte InvokeSByteMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticByteMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticByteMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe char InvokeCharMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticCharMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticCharMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe short InvokeInt16Method (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticShortMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticShortMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe int InvokeInt32Method (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticIntMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticIntMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe long InvokeInt64Method (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticLongMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticLongMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe float InvokeSingleMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticFloatMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticFloatMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe double InvokeDoubleMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticDoubleMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticDoubleMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
public unsafe JniObjectReference InvokeObjectMethod (string encodedMember, JniArgumentValue* parameters)
{
var m = GetMethodInfo (encodedMember);
- return JniEnvironment.StaticMethods.CallStaticObjectMethod (Members.JniPeerType.PeerReference, m, parameters);
+ return JniEnvironment.StaticMethods.CallStaticObjectMethod (GetMethodDeclaringType (m).PeerReference, m, parameters);
}
}}
}
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.cs
index 9e445be47..d2ffd424b 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.cs
@@ -12,7 +12,7 @@ public partial class JniPeerMembers {
private bool isInterface;
public JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool isInterface)
- : this (jniPeerTypeName, managedPeerType, checkManagedPeerType: true, isInterface: isInterface)
+ : this (jniPeerTypeName = GetReplacementType (jniPeerTypeName), managedPeerType, checkManagedPeerType: true, isInterface: isInterface)
{
}
diff --git a/tests/Java.Interop-Tests/Java.Interop-Tests.csproj b/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
index bed263368..4afa21e4e 100644
--- a/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
+++ b/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
@@ -53,14 +53,12 @@
+
+
-
-
-
-
-
+
diff --git a/tests/Java.Interop-Tests/Java.Interop-Tests.targets b/tests/Java.Interop-Tests/Java.Interop-Tests.targets
new file mode 100644
index 000000000..e3910c046
--- /dev/null
+++ b/tests/Java.Interop-Tests/Java.Interop-Tests.targets
@@ -0,0 +1,21 @@
+
+
+
+
+
+ <_Source Include="@(JavaInteropTestJar->Replace('%5c', '/'))" />
+
+
+
+
+
+
+
+
diff --git a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
index 855f52990..f289a1566 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
@@ -91,8 +91,8 @@ IEnumerable CreateSimpleReferencesEnumerator (Type type)
// "potentially non-existent" types ensures that we don't throw
// from places we don't want to internally throw.
return new[]{
- desugarType,
- $"{jniSimpleReference}$-CC"
+ $"{desugarType}$_CC", // For JniPeerMembersTests.DesugarInterfaceStaticMethod()
+ $"{jniSimpleReference}$-CC",
};
}
diff --git a/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs b/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
index 788f5e61e..875a67a0b 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
@@ -108,6 +108,38 @@ public void ReplaceInstanceMethodWithStaticMethod ()
// Shouldn't throw; should instead invoke ObjectHelper.getHashCodeHelper(Object)
o.remappedToStaticHashCode ();
}
+
+#if !__ANDROID__
+ // Note: this test looks up a static method from one class, then
+ // calls `JNIEnv::CallStaticObjectMethod()` passing in a jclass
+ // for a *different* class.
+ //
+ // This appears to work on Desktop JVM.
+ //
+ // On Android, this will ABORT the app:
+ // JNI DETECTED ERROR IN APPLICATION: can't call static int com.xamarin.interop.DesugarAndroidInterface$_CC.getClassName() with class java.lang.Class
+ // in call to CallStaticObjectMethodA
+ //
+ // *Fascinating* the differences that can appear between JVM implementations
+ [Test]
+ public unsafe void DoesTheJmethodNeedToMatchDeclaringType ()
+ {
+ var iface = new JniType ("com/xamarin/interop/AndroidInterface");
+ var desugar = new JniType ("com/xamarin/interop/DesugarAndroidInterface$_CC");
+ var m = desugar.GetStaticMethod ("getClassName", "()Ljava/lang/String;");
+
+ var r = JniEnvironment.StaticMethods.CallStaticObjectMethod (iface.PeerReference, m, null);
+ var s = JniEnvironment.Strings.ToString (ref r, JniObjectReferenceOptions.CopyAndDispose);
+ Assert.AreEqual ("DesugarAndroidInterface$-CC", s);
+ }
+#endif // !__ANDROID__
+
+ [Test]
+ public void DesugarInterfaceStaticMethod ()
+ {
+ var s = IAndroidInterface.getClassName ();
+ Assert.AreEqual ("DesugarAndroidInterface$-CC", s);
+ }
#endif // NET
}
@@ -208,4 +240,19 @@ public override unsafe int hashCode ()
return base.hashCode ();
}
}
+
+#if NET
+ [JniTypeSignature (JniTypeName)]
+ interface IAndroidInterface : IJavaPeerable {
+ internal const string JniTypeName = "com/xamarin/interop/AndroidInterface";
+
+ private static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (IAndroidInterface), isInterface: true);
+
+ public static unsafe string getClassName ()
+ {
+ var s = _members.StaticMethods.InvokeObjectMethod ("getClassName.()Ljava/lang/String;", null);
+ return JniEnvironment.Strings.ToString (ref s, JniObjectReferenceOptions.CopyAndDispose);
+ }
+ }
+#endif // NET
}
diff --git a/tests/Java.Interop-Tests/java/com/xamarin/interop/AndroidInterface.java b/tests/Java.Interop-Tests/java/com/xamarin/interop/AndroidInterface.java
new file mode 100644
index 000000000..dda252a47
--- /dev/null
+++ b/tests/Java.Interop-Tests/java/com/xamarin/interop/AndroidInterface.java
@@ -0,0 +1,14 @@
+package com.xamarin.interop;
+
+// When Android Desugaring is enabled -- the default when targeting API-25 and earlier --
+// certain Java constructs result in Java bytecode rewriting.
+// Interface static methods are *moved* into $-CC types.
+public interface AndroidInterface {
+
+ // When Desugaring is enabled, this is moved to `AndroidInterface$-CC.getClassName()`,
+ // and the original `AndroidInterface.getClassName()` *no longer exists*.
+
+ // public static String getClassName() {
+ // return "AndroidInterface";
+ // }
+}
diff --git a/tests/Java.Interop-Tests/java/com/xamarin/interop/DesugarAndroidInterface$_CC.java b/tests/Java.Interop-Tests/java/com/xamarin/interop/DesugarAndroidInterface$_CC.java
new file mode 100644
index 000000000..503814d73
--- /dev/null
+++ b/tests/Java.Interop-Tests/java/com/xamarin/interop/DesugarAndroidInterface$_CC.java
@@ -0,0 +1,8 @@
+package com.xamarin.interop;
+
+public class DesugarAndroidInterface$_CC {
+
+ public static String getClassName() {
+ return "DesugarAndroidInterface$-CC";
+ }
+}