Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Java.InteropTests {
public class JniRuntimeJniTypeManagerTests : JavaVMFixture {

[Test]
[Category ("TrimmableTypeMapUnsupported")]
[RequiresDynamicCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")]
[RequiresUnreferencedCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")]
public void GetInvokerType ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
/// // or: null; // no activation
/// // or: throw new NotSupportedException(...); // open generic
///
/// // JniName / TargetType / InvokerType are supplied by the base JavaPeerProxy constructor.
/// // JniName / TargetType are supplied by the base JavaPeerProxy constructor.
///
/// // UCO wrappers — [UnmanagedCallersOnly] entry points for JNI native methods (ACWs only):
/// public static void n_OnCreate_uco_0(IntPtr jnienv, IntPtr self, IntPtr p0)
Expand Down Expand Up @@ -731,22 +731,20 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<UcoWrapperTargetData, Me
if (useNonGenericBase) {
proxyBaseType = _javaPeerProxyNonGenericRef;
baseCtorRef = _pe.AddMemberRef (_javaPeerProxyNonGenericRef, ".ctor",
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (3,
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (2,
rt => rt.Void (),
p => {
p.AddParameter ().Type ().String ();
p.AddParameter ().Type ().Type (_systemTypeRef, false);
p.AddParameter ().Type ().Type (_systemTypeRef, false);
}));
} else {
var genericProxyBase = _pe.MakeGenericTypeSpec (_javaPeerProxyRef, targetTypeRef);
proxyBaseType = genericProxyBase;
baseCtorRef = _pe.AddMemberRef (genericProxyBase, ".ctor",
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (2,
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
rt => rt.Void (),
p => {
p.AddParameter ().Type ().String ();
p.AddParameter ().Type ().Type (_systemTypeRef, false);
}));
}

Expand All @@ -762,27 +760,21 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<UcoWrapperTargetData, Me
metadata.AddInterfaceImplementation (typeDefHandle, _iAndroidCallableWrapperRef);
}

// .ctor — pass the resolved JNI name, (for generic-definition base) target type, and
// optional invoker type to the base proxy constructor.
// .ctor — pass the resolved JNI name and (for generic-definition base) target type
// to the base proxy constructor.
var selfAttrCtorDef = _pe.EmitBody (".ctor",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (0, rt => rt.Void (), p => { }),
encoder => {
encoder.OpCode (ILOpCode.Ldarg_0);
encoder.LoadString (metadata.GetOrAddUserString (proxy.JniName));
if (useNonGenericBase) {
// Non-generic base ctor signature: (string, Type, Type?). Push the
// Non-generic base ctor signature: (string, Type). Push the
// target type (open-generic definition or interface) as the second argument.
encoder.LoadToken (targetTypeRef);
encoder.Call (_getTypeFromHandleRef, parameterCount: 1, returnsValue: true);
}
if (proxy.InvokerType != null) {
encoder.LoadToken (_pe.ResolveTypeRef (proxy.InvokerType));
encoder.Call (_getTypeFromHandleRef, parameterCount: 1, returnsValue: true);
} else {
encoder.OpCode (ILOpCode.Ldnull);
}
encoder.Call (baseCtorRef, parameterCount: useNonGenericBase ? 3 : 2, isInstance: true);
encoder.Call (baseCtorRef, parameterCount: useNonGenericBase ? 2 : 1, isInstance: true);
encoder.Return ();
});

Expand Down
16 changes: 2 additions & 14 deletions src/Mono.Android/Java.Interop/JavaPeerProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@ public abstract class JavaPeerProxy : Attribute
{
protected JavaPeerProxy (
string jniName,
Type targetType,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? invokerType)
Type targetType)
{
JniName = jniName ?? throw new ArgumentNullException (nameof (jniName));
TargetType = targetType ?? throw new ArgumentNullException (nameof (targetType));
Comment on lines 45 to 50
InvokerType = invokerType;
}

/// <summary>
Expand All @@ -72,13 +69,6 @@ protected JavaPeerProxy (
/// </summary>
public Type TargetType { get; }

/// <summary>
/// Gets the invoker type for interfaces and abstract classes.
/// Returns null for concrete types that can be directly instantiated.
/// </summary>
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public Type? InvokerType { get; }

/// <summary>
/// Gets a factory for creating containers (arrays, collections) of the target type.
/// Enables AOT-safe creation of generic collections without <c>MakeGenericType()</c>.
Expand Down Expand Up @@ -148,9 +138,7 @@ public abstract class JavaPeerProxy<
> : JavaPeerProxy where T : class, IJavaPeerable
{
protected JavaPeerProxy (
string jniName,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? invokerType) : base (jniName, typeof (T), invokerType)
string jniName) : base (jniName, typeof (T))
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,15 +493,6 @@ internal static bool TargetTypeMatches (Type targetType, Type proxyTargetType)
return targetType.IsAssignableFrom (proxyTargetType);
}

/// <summary>
/// Gets the invoker type for an interface or abstract class from the proxy attribute.
/// </summary>
[return: DynamicallyAccessedMembers (Constructors)]
internal Type? GetInvokerType (Type type)
{
return GetProxyForManagedType (type)?.InvokerType;
}

/// <summary>
/// Gets the container factory for a type from its proxy attribute.
/// Used for AOT-safe array/collection/dictionary creation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,10 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)

protected override Type? GetInvokerTypeCore (Type type)
{
var invokerType = TrimmableTypeMap.Instance.GetInvokerType (type);
if (invokerType != null) {
return invokerType;
}

return base.GetInvokerTypeCore (type);
throw new NotSupportedException (
$"GetInvokerTypeCore should not be called in the trimmable typemap path. " +
$"Peers for '{type.FullName}' are activated through the generated {nameof (JavaPeerProxy)}.CreateInstance, " +
$"so invoker types are never used.");
Comment on lines +99 to +102
}

protected override IReadOnlyList<string>? GetStaticMethodFallbackTypesCore (string jniSimpleReference)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@ public void Constructor_StoresJniNameAndTargetType ()

Assert.AreEqual ("custom/ExplicitName", proxy.JniName);
Assert.AreEqual (typeof (ProxyTestPeer), proxy.TargetType);
Assert.IsNull (proxy.InvokerType);
}

[Test]
public void Constructor_StoresInvokerType ()
public void GenericConstructor_StoresJniNameAndTargetType ()
{
var proxy = new InvokerProxy ();
var proxy = new GenericProxy ();

Assert.AreEqual ("custom/InvokerProxy", proxy.JniName);
Assert.AreEqual ("custom/GenericProxy", proxy.JniName);
Assert.AreEqual (typeof (ProxyTestPeer), proxy.TargetType);
Assert.AreEqual (typeof (ProxyTestPeerInvoker), proxy.InvokerType);
}
}

Expand All @@ -45,32 +43,20 @@ public ProxyTestPeer (IntPtr handle, JniHandleOwnership transfer)
}
}

sealed class ProxyTestPeerInvoker : Java.Lang.Object
{
public ProxyTestPeerInvoker ()
{
}

public ProxyTestPeerInvoker (IntPtr handle, JniHandleOwnership transfer)
: base (handle, transfer)
{
}
}

sealed class ExplicitNameProxy : JavaPeerProxy
{
public ExplicitNameProxy ()
: base ("custom/ExplicitName", typeof (ProxyTestPeer), invokerType: null)
: base ("custom/ExplicitName", typeof (ProxyTestPeer))
{
}

public override IJavaPeerable? CreateInstance (IntPtr handle, JniHandleOwnership transfer) => null;
}

sealed class InvokerProxy : JavaPeerProxy<ProxyTestPeer>
sealed class GenericProxy : JavaPeerProxy<ProxyTestPeer>
{
public InvokerProxy ()
: base ("custom/InvokerProxy", typeof (ProxyTestPeerInvoker))
public GenericProxy ()
: base ("custom/GenericProxy")
{
}

Expand Down