Browse Source

Merge pull request #102817 from dsnopek/java-class-wrapper-array-improvements

JavaClassWrapper: Improve handling of typed array arguments
Thaddeus Crews 5 months ago
parent
commit
8ef0075193
1 changed files with 249 additions and 43 deletions
  1. 249 43
      platform/android/java_class_wrapper.cpp

+ 249 - 43
platform/android/java_class_wrapper.cpp

@@ -132,6 +132,116 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
 						}
 					}
 				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::BOOL) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_BYTE:
+				case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
+					if (p_args[i]->get_type() != Variant::PACKED_BYTE_ARRAY) {
+						arg_expected = Variant::PACKED_BYTE_ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_SHORT:
+				case ARG_ARRAY_BIT | ARG_TYPE_INT: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::INT) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else if (p_args[i]->get_type() != Variant::PACKED_INT32_ARRAY) {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::INT) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else if (p_args[i]->get_type() != Variant::PACKED_INT64_ARRAY) {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::FLOAT) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else if (p_args[i]->get_type() != Variant::PACKED_FLOAT32_ARRAY) {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::FLOAT) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else if (p_args[i]->get_type() != Variant::PACKED_FLOAT64_ARRAY) {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_STRING:
+				case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::STRING) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else if (p_args[i]->get_type() != Variant::PACKED_STRING_ARRAY) {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::CALLABLE) {
+							arg_expected = Variant::ARRAY;
+						}
+					} else {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
+				case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
+					if (p_args[i]->get_type() == Variant::ARRAY) {
+						Array arr = *p_args[i];
+						if (arr.is_typed() && arr.get_typed_builtin() != Variant::OBJECT) {
+							arg_expected = Variant::ARRAY;
+						} else {
+							String cn = E.param_sigs[i].operator String();
+							if (cn.begins_with("[L") && cn.ends_with(";")) {
+								cn = cn.substr(2, cn.length() - 3);
+							}
+							jclass c = env->FindClass(cn.utf8().get_data());
+							if (c) {
+								for (int j = 0; j < arr.size(); j++) {
+									Ref<JavaObject> jo = arr[j];
+									if (jo.is_valid()) {
+										if (!env->IsInstanceOf(jo->instance, c)) {
+											arg_expected = Variant::ARRAY;
+											break;
+										}
+									} else {
+										arg_expected = Variant::ARRAY;
+										break;
+									}
+								}
+							} else {
+								arg_expected = Variant::ARRAY;
+							}
+						}
+					} else {
+						arg_expected = Variant::ARRAY;
+					}
+				} break;
 				default: {
 					if (p_args[i]->get_type() != Variant::ARRAY) {
 						arg_expected = Variant::ARRAY;
@@ -307,90 +417,171 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_BYTE: {
-				Array arr = *p_args[i];
-				jbyteArray a = env->NewByteArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jbyte val = arr[j];
-					env->SetByteArrayRegion(a, j, 1, &val);
+				jbyteArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewByteArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jbyte val = arr[j];
+						env->SetByteArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_BYTE_ARRAY) {
+					PackedByteArray arr = *p_args[i];
+					a = env->NewByteArray(arr.size());
+					env->SetByteArrayRegion(a, 0, arr.size(), (const jbyte *)arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
-				Array arr = *p_args[i];
-				jcharArray a = env->NewCharArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jchar val = arr[j];
-					env->SetCharArrayRegion(a, j, 1, &val);
+				jcharArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewCharArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jchar val = arr[j];
+						env->SetCharArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_BYTE_ARRAY) {
+					PackedByteArray arr = *p_args[i];
+					// The data is expected to be UTF-16 encoded, so the length is half the size of the byte array.
+					int size = arr.size() / 2;
+					a = env->NewCharArray(size);
+					env->SetCharArrayRegion(a, 0, size, (const jchar *)arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_SHORT: {
-				Array arr = *p_args[i];
-				jshortArray a = env->NewShortArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jshort val = arr[j];
-					env->SetShortArrayRegion(a, j, 1, &val);
+				jshortArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewShortArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jshort val = arr[j];
+						env->SetShortArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_INT32_ARRAY) {
+					PackedInt32Array arr = *p_args[i];
+					a = env->NewShortArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jshort val = arr[j];
+						env->SetShortArrayRegion(a, j, 1, &val);
+					}
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_INT: {
-				Array arr = *p_args[i];
-				jintArray a = env->NewIntArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jint val = arr[j];
-					env->SetIntArrayRegion(a, j, 1, &val);
+				jintArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewIntArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jint val = arr[j];
+						env->SetIntArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_INT32_ARRAY) {
+					PackedInt32Array arr = *p_args[i];
+					a = env->NewIntArray(arr.size());
+					env->SetIntArrayRegion(a, 0, arr.size(), arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
-				Array arr = *p_args[i];
-				jlongArray a = env->NewLongArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jlong val = (int64_t)arr[j];
-					env->SetLongArrayRegion(a, j, 1, &val);
+				jlongArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewLongArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jlong val = (int64_t)arr[j];
+						env->SetLongArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_INT64_ARRAY) {
+					PackedInt64Array arr = *p_args[i];
+					a = env->NewLongArray(arr.size());
+					env->SetLongArrayRegion(a, 0, arr.size(), arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
-				Array arr = *p_args[i];
-				jfloatArray a = env->NewFloatArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jfloat val = arr[j];
-					env->SetFloatArrayRegion(a, j, 1, &val);
+				jfloatArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewFloatArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jfloat val = arr[j];
+						env->SetFloatArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+					PackedFloat32Array arr = *p_args[i];
+					a = env->NewFloatArray(arr.size());
+					env->SetFloatArrayRegion(a, 0, arr.size(), arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
-				Array arr = *p_args[i];
-				jdoubleArray a = env->NewDoubleArray(arr.size());
-				for (int j = 0; j < arr.size(); j++) {
-					jdouble val = arr[j];
-					env->SetDoubleArrayRegion(a, j, 1, &val);
+				jdoubleArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewDoubleArray(arr.size());
+					for (int j = 0; j < arr.size(); j++) {
+						jdouble val = arr[j];
+						env->SetDoubleArrayRegion(a, j, 1, &val);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_FLOAT64_ARRAY) {
+					PackedFloat64Array arr = *p_args[i];
+					a = env->NewDoubleArray(arr.size());
+					env->SetDoubleArrayRegion(a, 0, arr.size(), arr.ptr());
 				}
+
 				argv[i].l = a;
 				to_free.push_back(a);
 
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_STRING:
 			case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
-				Array arr = *p_args[i];
-				jobjectArray a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
-				for (int j = 0; j < arr.size(); j++) {
-					String s = arr[j];
-					jstring jStr = env->NewStringUTF(s.utf8().get_data());
-					env->SetObjectArrayElement(a, j, jStr);
-					to_free.push_back(jStr);
+				jobjectArray a = nullptr;
+
+				if (p_args[i]->get_type() == Variant::ARRAY) {
+					Array arr = *p_args[i];
+					a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
+					for (int j = 0; j < arr.size(); j++) {
+						String s = arr[j];
+						jstring jStr = env->NewStringUTF(s.utf8().get_data());
+						env->SetObjectArrayElement(a, j, jStr);
+						to_free.push_back(jStr);
+					}
+				} else if (p_args[i]->get_type() == Variant::PACKED_STRING_ARRAY) {
+					PackedStringArray arr = *p_args[i];
+					a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
+					for (int j = 0; j < arr.size(); j++) {
+						String s = arr[j];
+						jstring jStr = env->NewStringUTF(s.utf8().get_data());
+						env->SetObjectArrayElement(a, j, jStr);
+						to_free.push_back(jStr);
+					}
 				}
 
 				argv[i].l = a;
@@ -410,7 +601,22 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
 				to_free.push_back(jarr);
 			} break;
 			case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
-				argv[i].l = nullptr;
+				String cn = method->param_sigs[i].operator String();
+				if (cn.begins_with("[L") && cn.ends_with(";")) {
+					cn = cn.substr(2, cn.length() - 3);
+				}
+				jclass c = env->FindClass(cn.utf8().get_data());
+				if (c) {
+					Array arr = *p_args[i];
+					jobjectArray jarr = env->NewObjectArray(arr.size(), c, nullptr);
+					for (int j = 0; j < arr.size(); j++) {
+						Ref<JavaObject> jo = arr[j];
+						env->SetObjectArrayElement(jarr, j, jo->instance);
+					}
+
+					argv[i].l = jarr;
+					to_free.push_back(jarr);
+				}
 			} break;
 		}
 	}