Commit 3fee05c
[Java.Interop, generator] Fix GetPeerMembers for interfaces (#486)
Context: dotnet/android#3533
Consider the following Java interface which contains a default
interface method:
// Java
package com.xamarin.android;
public interface DefaultMethodsInterface
{
default int foo () { return 0; }
}
This is bound as:
// C# Binding
public partial interface IDefaultMethodsInterface : IJavaPeerable {
static readonly JniPeerMembers _members = new JniPeerMembers (
"java/DefaultMethodsInterface",
typeof (IDefaultMethodsInterface));
[Register ("foo", "()V", "…")]
virtual unsafe int Foo ()
{
return _members.InstanceMethods.InvokeVirtualInt32Method ("foo.()V", this, null);
}
}
If we "implement" the interface from C# *without* implementing
`IDefaultMethodsInterface.Foo()`:
// C#
class ManagedOverrideDefault : Java.Lang.Object, IDefaultMethodsInterface
{
}
Then invoke the default interface method:
var over = new ManagedOverrideDefault ();
(over as IDefaultMethodsInterface).Foo ();
The attempt to invoke the default implementation of
`IDefaultMethodsInterface.Foo()` causes a crash:
Java.Lang.NoSuchMethodError : no non-static method "Ljava/lang/Object;.foo()I"
The cause of the crash is as follows: `IDefaultMethodsInterface.Foo()`
calls `JniPeerMembers.JniInstanceMethods.InvokeVirtualInt32Method()`
tries to determine if the method is overridden, and if the method is
*not* overridden -- as is the case here -- then we hit the non-virtual
invocation path:
// src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs
var j = Members.GetPeerMembers (self);
var n = j.InstanceMethods.GetMethodInfo (encodedMember);
return JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
`JniInstanceMethods.Members` will be the
`IDefaultMethodsInterface._members` field, and
`Members.GetPeerMembers()` would return `self.JniPeerMembers`.
Because this is a C# class which inherits `Java.Lang.Object`,
`Java.Lang.Object._members` is returned. We then attempt to resolve
`foo()` from `java.lang.Object`, which *does not exist*, which is why
the `NoSuchMethodError` is thrown.
The fix is to "intercept" the `Members.GetPeerMembers()` invocation
so that `j` refers to `IDefaultMethodsInterface._members`, *not*
`Java.Lang.Object._members`. This would allow `n` to refer to
`DefaultMethodsInterface.foo()`, which *does* exist, and *can* be
invoked via `JniEnvironment.InstanceMethods.CallNonvirtualIntMethod()`.
Add the following `JniPeerMembers` constructor overload:
partial class JniPeerMembers {
public JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool isInterface);
}
Update `JniPeerMembers.GetPeerMembers()` so that if `isInterface` is
true, we return `this` (the *interface*s `JniPeerMembers` instance).
Update `generator` so that `_members` construction within interfaces
sets the `isInterface` parameter to true, resulting in:
partial interface IDefaultMethodsInterface {
static readonly JniPeerMembers _members = new JniPeerMembers (
"java/DefaultMethodsInterface",
typeof (IDefaultMethodsInterface),
isInterface: true);
}
This allows `(over as IDefaultMethodsInterface).Foo()` to work
without an exception being thrown.1 parent 29f9707 commit 3fee05c
File tree
9 files changed
+25
-15
lines changed- src/Java.Interop/Java.Interop
- tools/generator
- Java.Interop.Tools.Generator.CodeGeneration
- Tests/Unit-Tests/CodeGeneratorExpectedResults
- JavaInterop1
- XAJavaInterop1
9 files changed
+25
-15
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
351 | 351 | | |
352 | 352 | | |
353 | 353 | | |
| 354 | + | |
354 | 355 | | |
355 | 356 | | |
356 | 357 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
10 | 17 | | |
11 | | - | |
| 18 | + | |
12 | 19 | | |
13 | 20 | | |
14 | 21 | | |
| |||
27 | 34 | | |
28 | 35 | | |
29 | 36 | | |
30 | | - | |
| 37 | + | |
31 | 38 | | |
32 | 39 | | |
33 | 40 | | |
| |||
51 | 58 | | |
52 | 59 | | |
53 | 60 | | |
| 61 | + | |
| 62 | + | |
54 | 63 | | |
55 | 64 | | |
56 | 65 | | |
| |||
140 | 149 | | |
141 | 150 | | |
142 | 151 | | |
143 | | - | |
| 152 | + | |
144 | 153 | | |
145 | 154 | | |
146 | 155 | | |
| |||
Lines changed: 6 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
262 | 262 | | |
263 | 263 | | |
264 | 264 | | |
265 | | - | |
| 265 | + | |
266 | 266 | | |
267 | 267 | | |
268 | | - | |
| 268 | + | |
269 | 269 | | |
270 | 270 | | |
271 | 271 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
0 commit comments