You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Java.Interop] JniValueManager.CreatePeer() tries more types (#1328)
Context: 77a6bf8
Context: dotnet/android#9962
While investigating dotnet/android#9962, we observed "curious"
behavior around `JniRuntime.JniValueManager.CreatePeer()`, simplified
in this unit test fragment:
JniObjectReference float_ref;
using (var value = new Java.Lang.Float (1.0f)) {
float_ref = value.PeerReference.NewLocalRef ();
}
var peer = JniEnvironment.Runtime.ValueManager.CreatePeer (
ref float_ref,
JniObjectReferenceOptions.Copy,
targetType: null);
Assert.IsNotNull (peer, "Could not create Java.Lang.Float peer!");
Assert.AreEqual (
typeof (Java.Lang.Float),
peer.GetType (),
$"Peer type mismatch: expected Java.Lang.Float, got {peer.GetType ()}");
What *actually* happened was that the type assertion failed:
Error Message:
Peer type mismatch: expected Java.Lang.Float, got Java.Interop.JavaObject
Expected: <Java.Lang.Float>
But was: <Java.Interop.JavaObject>
`float_ref` is a `java.lang.Float`. Why is `CreatePeer()` creating a
`JavaObject`?
The reason why `CreatePeer()` created a `JavaObject` instance is tied
to the semantics of
`JniRuntime.JniTypeManager.GetType(JniTypeSignature)`, which in turn
is influenced by 77a6bf8, which basically said "wouldn't it be cool
if `float?` could be projected as `java.lang.Float`"? This would
allow `null` to be represented:
partial class ExportTest {
[JavaCallable ("staticActionNullableFloat", Signature="(Ljava/lang/Float;)V")]
public static void StaticActionNullableFloat (float? f)
{
}
}
It makes sense! (Kinda?)
However, because of *when* "builtin" mappings are checked within
`JniRuntime.JniTypeManager.GetType(JniTypeSignature)` -- *very early*
-- this meant that when looking up the `Type` for `java/lang/Float`,
`GetType(JniTypeSignature)` would return `System.Single?` and *not*
`Java.Lang.Float`. As `System.Single?` does not implement
`IJavaPeerable`, `JniRuntime.JniValueManager.CreatePeerInstance()`
would *skip over* it, and ultimately hit `JavaObject` as a fallback.
Fix this by having `JniRuntime.JniValueManager.CreatePeerInstance()`
call `JniRuntime.JniTypeManager.GetTypes(JniTypeSignature)` instead
of `.GetType(JniTypeSignature)`. This will allow it to find the
binding for `Java.Lang.Float`, which *ISA* `IJavaPeerable`, allowing
an instance with the appropriate type to be created and returned by
`CreatePeer()`.
0 commit comments