Skip to content

Commit 05eddd9

Browse files
authored
[generator] Add string cast to prevent CS1503 (#970)
Fixes: #967 Context: dotnet/android-libraries#504 Context: #424 Context: #586 Context: #918 Java generics continues to be a "difficulty" in creating bindings. Consider [`ActivityResultContracts.RequestPermission`][0]: // Java public abstract /* partial */ class ActivityResultContract<I, O> { public abstract Intent createIntent(Context context, I input); } public /* partial */ class /* ActivityResultContracts. */ RequestPermission extends ActivityResultContract<String, Boolean> { @OverRide public Intent createIntent(Context context, String input) {…} } The JNI Signature for `ActivityResultContracts.RequestPermission.createIntent()` is `(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;`, i.e. `class-parse` & `generator` believe that the `input` parameter is of type `String`, which we bind by default as `string`. Thus: // C# public abstract partial class ActivityResultContract { public abstract Intent CreateIntent (Context? context, Java.Lang.Object? input) => … } public partial class /* ActivityResultContracts. */ RequestPermission { public override Intent CreateIntent (Context? context, string? input) => … } This fails to compile with a [CS0115][1]: 'RequestPermission.CreateIntent(Context?, string?)': no suitable method found to override as the `input` parameter of `RequestPermission.CreateIntent()` changes from `Java.Lang.Object?` to `string?`. We can attempt to address this via Metadata: <attr path="/api/package[@name='androidx.activity.result.contract']/class[@name='ActivityResultContracts.RequestPermission']/method[@name='createIntent' and count(parameter)=2 and parameter[1][@type='android.content.Context'] and parameter[2][@type='java.lang.String']]" name="managedType" >Java.Lang.Object</attr> This fixes one error, as `generator` now emits: public partial class /* ActivityResultContracts. */ RequestPermission { [Register ("createIntent", "(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;", "")] public override unsafe global::Android.Content.Intent CreateIntent (global::Android.Content.Context context, global::Java.Lang.Object input) { const string __id = "createIntent.(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;"; IntPtr native_input = JNIEnv.NewString (input); try { JniArgumentValue* __args = stackalloc JniArgumentValue [2]; __args [0] = new JniArgumentValue ((context == null) ? IntPtr.Zero : ((global::Java.Lang.Object) context).Handle); __args [1] = new JniArgumentValue (native_input); var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); return global::Java.Lang.Object.GetObject<global::Android.Content.Intent> (__rm.Handle, JniHandleOwnership.TransferLocalRef); } finally { JNIEnv.DeleteLocalRef (native_input); global::System.GC.KeepAlive (context); global::System.GC.KeepAlive (input); } } } The `override` method declaration is correct. However, this introduces a [CS1503][2] error: IntPtr native_input = JNIEnv.NewString (input); // Error CS1503 Argument 1: cannot convert from 'Java.Lang.Object' to 'string?' The workaround is to remove `createIntent()` ~entirely, and manually bind it, as done in dotnet/android-libraries#512. Fix this issue by always emitting a cast to `(string)` as part of the `JNIEnv.NewString()` invocation, instead emitting: IntPtr native_input = JNIEnv.NewString ((string?) input); This works because `Java.Lang.Object` defines an [explicit conversion to `string?`][3], and if a `Java.Lang.String` instance is provided to the `input` parameter, it's equivalent to calling `.ToString()`. This fix allows the original suggested Metadata solution to work. [0]: https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestPermission [1]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0115 [2]: https://docs.microsoft.com/en-us/dotnet/csharp/misc/cs1503 [3]: https://github.com/xamarin/xamarin-android/blob/a58d4e9706455227eabb6e5b5103b25da716688b/src/Mono.Android/Java.Lang/Object.cs#L434-L439
1 parent 37cff25 commit 05eddd9

29 files changed

+39
-39
lines changed

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokers.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public unsafe int GetCountForKey (string key)
2121
{
2222
if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero)
2323
id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I");
24-
IntPtr native_key = JNIEnv.NewString (key);
24+
IntPtr native_key = JNIEnv.NewString ((string)key);
2525
JValue* __args = stackalloc JValue [1];
2626
__args [0] = new JValue (native_key);
2727
var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokersWithSkips.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public unsafe int GetCountForKey (string key)
2121
{
2222
if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero)
2323
id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I");
24-
IntPtr native_key = JNIEnv.NewString (key);
24+
IntPtr native_key = JNIEnv.NewString ((string)key);
2525
JValue* __args = stackalloc JValue [1];
2626
__args [0] = new JValue (native_key);
2727
var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokers.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public unsafe string Key {
9191
set {
9292
if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero)
9393
id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V");
94-
IntPtr native_value = JNIEnv.NewString (value);
94+
IntPtr native_value = JNIEnv.NewString ((string)value);
9595
JValue* __args = stackalloc JValue [1];
9696
__args [0] = new JValue (native_value);
9797
JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokersWithSkips.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public unsafe string Key {
4242
set {
4343
if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero)
4444
id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V");
45-
IntPtr native_value = JNIEnv.NewString (value);
45+
IntPtr native_value = JNIEnv.NewString ((string)value);
4646
JValue* __args = stackalloc JValue [1];
4747
__args [0] = new JValue (native_value);
4848
JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClass.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public partial class MyClass {
3737
if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
3838
return;
3939

40-
IntPtr native_p0 = JNIEnv.NewString (p0);
40+
IntPtr native_p0 = JNIEnv.NewString ((string?)p0);
4141
try {
4242
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
4343
__args [0] = new JniArgumentValue (native_p0);
@@ -153,7 +153,7 @@ public partial class MyClass {
153153
[Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")]
154154
set {
155155
const string __id = "set_Key.(Ljava/lang/String;)V";
156-
IntPtr native_value = JNIEnv.NewString (value);
156+
IntPtr native_value = JNIEnv.NewString ((string?)value);
157157
try {
158158
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
159159
__args [0] = new JniArgumentValue (native_value);
@@ -253,7 +253,7 @@ public partial class MyClass {
253253
public virtual unsafe int GetCountForKey (string? key)
254254
{
255255
const string __id = "GetCountForKey.(Ljava/lang/String;)I";
256-
IntPtr native_key = JNIEnv.NewString (key);
256+
IntPtr native_key = JNIEnv.NewString ((string?)key);
257257
try {
258258
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
259259
__args [0] = new JniArgumentValue (native_key);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterface.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterf
223223
set {
224224
if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero)
225225
id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V");
226-
IntPtr native_value = JNIEnv.NewString (value);
226+
IntPtr native_value = JNIEnv.NewString ((string?)value);
227227
JValue* __args = stackalloc JValue [1];
228228
__args [0] = new JValue (native_value);
229229
JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args);
@@ -303,7 +303,7 @@ internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterf
303303
{
304304
if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero)
305305
id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I");
306-
IntPtr native_key = JNIEnv.NewString (key);
306+
IntPtr native_key = JNIEnv.NewString ((string?)key);
307307
JValue* __args = stackalloc JValue [1];
308308
__args [0] = new JValue (native_key);
309309
var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClass.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public partial class MyClass {
3737
if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
3838
return;
3939

40-
IntPtr native_p0 = JNIEnv.NewString (p0);
40+
IntPtr native_p0 = JNIEnv.NewString ((string)p0);
4141
try {
4242
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
4343
__args [0] = new JniArgumentValue (native_p0);
@@ -153,7 +153,7 @@ public partial class MyClass {
153153
[Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")]
154154
set {
155155
const string __id = "set_Key.(Ljava/lang/String;)V";
156-
IntPtr native_value = JNIEnv.NewString (value);
156+
IntPtr native_value = JNIEnv.NewString ((string)value);
157157
try {
158158
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
159159
__args [0] = new JniArgumentValue (native_value);
@@ -253,7 +253,7 @@ public partial class MyClass {
253253
public virtual unsafe int GetCountForKey (string key)
254254
{
255255
const string __id = "GetCountForKey.(Ljava/lang/String;)I";
256-
IntPtr native_key = JNIEnv.NewString (key);
256+
IntPtr native_key = JNIEnv.NewString ((string)key);
257257
try {
258258
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
259259
__args [0] = new JniArgumentValue (native_key);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterface.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterf
223223
set {
224224
if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero)
225225
id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V");
226-
IntPtr native_value = JNIEnv.NewString (value);
226+
IntPtr native_value = JNIEnv.NewString ((string)value);
227227
JValue* __args = stackalloc JValue [1];
228228
__args [0] = new JValue (native_value);
229229
JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args);
@@ -303,7 +303,7 @@ internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterf
303303
{
304304
if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero)
305305
id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I");
306-
IntPtr native_key = JNIEnv.NewString (key);
306+
IntPtr native_key = JNIEnv.NewString ((string)key);
307307
JValue* __args = stackalloc JValue [1];
308308
__args [0] = new JValue (native_key);
309309
var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XamarinAndroid/WriteClass.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public partial class MyClass {
4848
if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
4949
return;
5050

51-
IntPtr native_p0 = JNIEnv.NewString (p0);
51+
IntPtr native_p0 = JNIEnv.NewString ((string)p0);
5252
try {
5353
JValue* __args = stackalloc JValue [1];
5454
__args [0] = new JValue (native_p0);
@@ -193,7 +193,7 @@ public partial class MyClass {
193193
set {
194194
if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero)
195195
id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V");
196-
IntPtr native_value = JNIEnv.NewString (value);
196+
IntPtr native_value = JNIEnv.NewString ((string)value);
197197
try {
198198
JValue* __args = stackalloc JValue [1];
199199
__args [0] = new JValue (native_value);
@@ -299,7 +299,7 @@ public partial class MyClass {
299299
{
300300
if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero)
301301
id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I");
302-
IntPtr native_key = JNIEnv.NewString (key);
302+
IntPtr native_key = JNIEnv.NewString ((string)key);
303303
try {
304304
JValue* __args = stackalloc JValue [1];
305305
__args [0] = new JValue (native_key);

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XamarinAndroid/WriteClassConstructors.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static IntPtr id_ctor_Ljava_lang_String_;
3737
if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
3838
return;
3939

40-
IntPtr native_p0 = JNIEnv.NewString (p0);
40+
IntPtr native_p0 = JNIEnv.NewString ((string)p0);
4141
try {
4242
JValue* __args = stackalloc JValue [1];
4343
__args [0] = new JValue (native_p0);

0 commit comments

Comments
 (0)