Skip to content

Commit

Permalink
Merge branch 'main' into dev/grendel/perfetto-integration
Browse files Browse the repository at this point in the history
* main:
  [Mono.Android] JavaCast<T>() should throw on unsupported types (#9145)
  Localized file check-in by OneLocBuild Task (#9149)
  • Loading branch information
grendello committed Jul 26, 2024
2 parents d42ce6b + 9a27140 commit 9554fb6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 45 deletions.
49 changes: 6 additions & 43 deletions src/Mono.Android/Java.Interop/JavaObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,41 +81,9 @@ internal static TResult? _JavaCast<
if (instance.Handle == IntPtr.Zero)
throw new ObjectDisposedException (instance.GetType ().FullName);

Type resultType = typeof (TResult);
if (resultType.IsClass) {
return (TResult) CastClass (instance, resultType);
}
else if (resultType.IsInterface) {
return (TResult?) Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, resultType);
}
else
throw new NotSupportedException (FormattableString.Invariant ($"Unable to convert type '{instance.GetType ().FullName}' to '{resultType.FullName}'."));
}

static IJavaObject CastClass (
IJavaObject instance,
[DynamicallyAccessedMembers (Constructors)]
Type resultType)
{
var klass = JNIEnv.FindClass (resultType);
try {
if (klass == IntPtr.Zero)
throw new ArgumentException ("Unable to determine JNI class for '" + resultType.FullName + "'.", "TResult");
if (!JNIEnv.IsInstanceOf (instance.Handle, klass))
throw new InvalidCastException (
FormattableString.Invariant ($"Unable to convert instance of type '{instance.GetType ().FullName}' to type '{resultType.FullName}'."));
} finally {
JNIEnv.DeleteGlobalRef (klass);
}

if (resultType.IsAbstract) {
// TODO: keep in sync with TypeManager.CreateInstance() algorithm
var invokerType = GetInvokerType (resultType);
if (invokerType == null)
throw new ArgumentException ("Unable to get Invoker for abstract type '" + resultType.FullName + "'.", "TResult");
resultType = invokerType;
}
return (IJavaObject) TypeManager.CreateProxy (resultType, instance.Handle, JniHandleOwnership.DoNotTransfer);
return (TResult) Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, typeof (TResult)) ??
throw new InvalidCastException (
FormattableString.Invariant ($"Unable to convert instance of type '{instance.GetType ().FullName}' to type '{typeof (TResult).FullName}'."));
}

internal static IJavaObject? JavaCast (
Expand All @@ -132,14 +100,9 @@ static IJavaObject CastClass (
if (resultType.IsAssignableFrom (instance.GetType ()))
return instance;

if (resultType.IsClass) {
return CastClass (instance, resultType);
}
else if (resultType.IsInterface) {
return (IJavaObject?) Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, resultType);
}
else
throw new NotSupportedException (FormattableString.Invariant ($"Unable to convert type '{instance.GetType ().FullName}' to '{resultType.FullName}'."));
return (IJavaObject?) Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, resultType) ??
throw new InvalidCastException (
FormattableString.Invariant ($"Unable to convert instance of type '{instance.GetType ().FullName}' to type '{resultType.FullName}'."));
}

// typeof(Foo) -> FooInvoker
Expand Down
1 change: 0 additions & 1 deletion src/Mono.Android/Java.Interop/TypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership

handleClass = JniEnvironment.Types.GetObjectClass (new JniObjectReference (handle));
if (!JniEnvironment.Types.IsAssignableFrom (handleClass, typeClass)) {
Logger.Log (LogLevel.Info, "*jonp*", $"# jonp: can't assign `{GetClassName(handleClass.Handle)}` to `{GetClassName(typeClass.Handle)}`");
return null;
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ Aby użyć niestandardowej ścieżki zestawu JDK dla kompilacji wiersza poleceni
{1} - NuGet package version</comment>
</data>
<data name="XA0141" xml:space="preserve">
<value>Pakiet NuGet „{0}” w wersji „{1}” zawiera bibliotekę udostępnioną „{2}”, która nie jest poprawnie wyrównana. Zobacz https://developer.android.com/guide/practices/page-sizes for more details</value>
<value>Pakiet NuGet „{0}” w wersji „{1}” zawiera bibliotekę udostępnioną „{2}”, która nie jest poprawnie wyrównana. Zobacz https://developer.android.com/guide/practices/page-sizes, aby uzyskać więcej szczegółów</value>
<comment>The following is a literal name and should not be translated: NuGet
{0} - NuGet package id
{1} - NuGet package version
Expand Down
26 changes: 26 additions & 0 deletions tests/Mono.Android-Tests/Java.Interop/JavaObjectExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,32 @@ public void JavaCast_InterfaceCast ()
}
}

[Test]
public void JavaCast_BadInterfaceCast ()
{
using var n = new Java.Lang.Integer (42);
var e = Assert.Catch<Exception>(() => JavaObjectExtensions.JavaCast<Java.Lang.IAppendable> (n));
if (e is System.Reflection.TargetInvocationException tie) {
// .NET 8 behavior
Assert.IsTrue (tie.InnerException is InvalidCastException);
} else if (e is InvalidCastException ice) {
// Yay
} else {
Assert.Fail ($"Unexpected exception type: {e.GetType ()}: {e.ToString ()}");
}
}

[Test]
public void JavaCast_ObtainOriginalInstance ()
{
using var list = new Java.Util.ArrayList ();
using var copy = new Java.Lang.Object (list.Handle, JniHandleOwnership.DoNotTransfer);
using var al = JavaObjectExtensions.JavaCast<Java.Util.AbstractList> (copy);

// Semantic change: in .NET 8, `al` is a new `AbstractListInvoker` instance, not `list`
Assert.AreSame (list, al);
}

[Test]
public void JavaCast_InvalidTypeCastThrows ()
{
Expand Down

0 comments on commit 9554fb6

Please sign in to comment.