Skip to content

[Java.Interop] CreatePeer() must satisfy targetType #1308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)
IJavaPeerable? CreatePeerInstance (
ref JniObjectReference klass,
[DynamicallyAccessedMembers (Constructors)]
Type fallbackType,
Type targetType,
ref JniObjectReference reference,
JniObjectReferenceOptions transfer)
{
Expand All @@ -362,7 +362,7 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)

type = Runtime.TypeManager.GetType (sig);

if (type != null) {
if (type != null && targetType.IsAssignableFrom (type)) {
var peer = TryCreatePeerInstance (ref reference, transfer, type);

if (peer != null) {
Expand All @@ -381,7 +381,7 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)
}
JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);

return TryCreatePeerInstance (ref reference, transfer, fallbackType);
return TryCreatePeerInstance (ref reference, transfer, targetType);
}

IJavaPeerable? TryCreatePeerInstance (
Expand Down
1 change: 1 addition & 0 deletions tests/Java.Interop-Tests/Java.Interop-Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
</ItemGroup>

<ItemGroup>
<JavaInteropTestJar Include="$(MSBuildThisFileDirectory)java\net\dot\jni\test\AnotherJavaInterfaceImpl.java" />
<JavaInteropTestJar Include="$(MSBuildThisFileDirectory)java\net\dot\jni\test\CrossReferenceBridge.java" />
<JavaInteropTestJar Include="$(MSBuildThisFileDirectory)java\net\dot\jni\test\CallNonvirtualBase.java" />
<JavaInteropTestJar Include="$(MSBuildThisFileDirectory)java\net\dot\jni\test\CallNonvirtualDerived.java" />
Expand Down
1 change: 1 addition & 0 deletions tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class JavaVMFixtureTypeManager : JniRuntime.JniTypeManager {
[GenericHolder<int>.JniTypeName] = typeof (GenericHolder<>),
[RenameClassBase.JniTypeName] = typeof (RenameClassBase),
[RenameClassDerived.JniTypeName] = typeof (RenameClassDerived),
[AnotherJavaInterfaceImpl.JniTypeName] = typeof (AnotherJavaInterfaceImpl),
[CallVirtualFromConstructorBase.JniTypeName] = typeof (CallVirtualFromConstructorBase),
[CallVirtualFromConstructorDerived.JniTypeName] = typeof (CallVirtualFromConstructorDerived),
[CrossReferenceBridge.JniTypeName] = typeof (CrossReferenceBridge),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ public void CollectPeers ()
// TODO
}

[Test]
public void CreatePeer_InvalidHandleReturnsNull ()
{
var r = new JniObjectReference ();
var o = valueManager.CreatePeer (ref r, JniObjectReferenceOptions.Copy, null);
Assert.IsNull (o);
}

[Test]
public unsafe void CreatePeer_UsesFallbackType ()
{
using var t = new JniType (AnotherJavaInterfaceImpl.JniTypeName);

var ctor = t.GetConstructor ("()V");
var lref = t.NewObject (ctor, null);

using var p = valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.CopyAndDispose, typeof (IJavaInterface));

Assert.IsFalse (lref.IsValid); // .CopyAndDispose disposes

Assert.IsNotNull (p);
Assert.AreSame (typeof (IJavaInterfaceInvoker), p!.GetType ());
}

[Test]
public void CreateValue ()
{
Expand Down Expand Up @@ -294,4 +318,38 @@ public class JniRuntimeJniValueManagerContract_NoGCIntegration : JniRuntimeJniVa
protected override Type ValueManagerType => ManagedValueManagerType;
}
#endif // !__ANDROID__

// Note: Java side implements JavaInterface, while managed binding DOES NOT.
// This is so that `CreatePeer(…, typeof(IJavaInterface))` tests don't use an existing AnotherJavaInterfaceImpl instance.
//
// This is mostly identical to MyJavaInterfaceImpl; the important difference is that
// it contains an activation constructor, while MyJavaInterfaceImpl does not.
// MyJavaInterfaceImpl can't have one, as that's what provokes the NotSupportedException in the JavaAs() tests.
//
// We want one here so that in "bad" `CreatePeer()` implementations, we'll find this peer and construct it
// before verifying that it satisfies the targetType requirement.
[JniTypeSignature (JniTypeName, GenerateJavaPeer=false)]
public class AnotherJavaInterfaceImpl : JavaObject {
internal const string JniTypeName = "net/dot/jni/test/AnotherJavaInterfaceImpl";

internal static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (AnotherJavaInterfaceImpl));

public override JniPeerMembers JniPeerMembers {
get {return _members;}
}

AnotherJavaInterfaceImpl (ref JniObjectReference reference, JniObjectReferenceOptions options)
: base (ref reference, options)
{
}

public unsafe AnotherJavaInterfaceImpl ()
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
{
const string id = "()V";
var peer = _members.InstanceMethods.StartCreateInstance (id, GetType (), null);
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
_members.InstanceMethods.FinishCreateInstance (id, this, null);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.dot.jni.test;

public class AnotherJavaInterfaceImpl
implements JavaInterface, Cloneable
{
public String getValue() {
return "Another hello from Java!";
}

public Object clone() {
return this;
}
}