Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/android/java_class_wrapper.cpp
11351 views
1
/**************************************************************************/
2
/* java_class_wrapper.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "api/java_class_wrapper.h"
32
33
#include "jni_utils.h"
34
#include "thread_jandroid.h"
35
36
bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret) {
37
HashMap<StringName, List<MethodInfo>>::Iterator M = methods.find(p_method);
38
if (!M) {
39
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
40
return false;
41
}
42
43
JNIEnv *env = get_jni_env();
44
ERR_FAIL_NULL_V(env, false);
45
46
env->PushLocalFrame(p_argcount);
47
48
MethodInfo *method = nullptr;
49
for (MethodInfo &E : M->value) {
50
if (!p_instance && !E._static && !E._constructor) {
51
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
52
continue;
53
}
54
55
int pc = E.param_types.size();
56
if (p_argcount < pc) {
57
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
58
r_error.expected = pc;
59
continue;
60
}
61
if (p_argcount > pc) {
62
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
63
r_error.expected = pc;
64
continue;
65
}
66
uint32_t *ptypes = E.param_types.ptrw();
67
bool valid = true;
68
69
for (int i = 0; i < pc; i++) {
70
Variant::Type arg_expected = Variant::NIL;
71
switch (ptypes[i]) {
72
case ARG_TYPE_VOID: {
73
//bug?
74
} break;
75
case ARG_TYPE_BOOLEAN: {
76
if (p_args[i]->get_type() != Variant::BOOL) {
77
arg_expected = Variant::BOOL;
78
}
79
} break;
80
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BYTE:
81
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_CHAR:
82
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_SHORT:
83
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_INT:
84
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_LONG:
85
case ARG_TYPE_BYTE:
86
case ARG_TYPE_CHAR:
87
case ARG_TYPE_SHORT:
88
case ARG_TYPE_INT:
89
case ARG_TYPE_LONG: {
90
if (!p_args[i]->is_num()) {
91
arg_expected = Variant::INT;
92
}
93
} break;
94
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_FLOAT:
95
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_DOUBLE:
96
case ARG_TYPE_FLOAT:
97
case ARG_TYPE_DOUBLE: {
98
if (!p_args[i]->is_num()) {
99
arg_expected = Variant::FLOAT;
100
}
101
} break;
102
case ARG_TYPE_STRING:
103
case ARG_TYPE_CHARSEQUENCE: {
104
if (!p_args[i]->is_string()) {
105
arg_expected = Variant::STRING;
106
}
107
} break;
108
case ARG_TYPE_CALLABLE: {
109
if (p_args[i]->get_type() != Variant::CALLABLE) {
110
arg_expected = Variant::CALLABLE;
111
}
112
} break;
113
case ARG_TYPE_CLASS: {
114
String cn = E.param_sigs[i].operator String();
115
if (cn.begins_with("L") && cn.ends_with(";")) {
116
cn = cn.substr(1, cn.length() - 2);
117
}
118
if (cn == "org/godotengine/godot/Dictionary") {
119
if (p_args[i]->get_type() != Variant::DICTIONARY) {
120
arg_expected = Variant::DICTIONARY;
121
}
122
} else if (p_args[i]->get_type() != Variant::OBJECT && p_args[i]->get_type() != Variant::NIL) {
123
arg_expected = Variant::OBJECT;
124
} else {
125
Ref<RefCounted> ref = *p_args[i];
126
if (ref.is_valid()) {
127
if (Object::cast_to<JavaObject>(ref.ptr())) {
128
Ref<JavaObject> jo = ref;
129
jclass c = jni_find_class(env, cn.utf8().get_data());
130
if (!c || !env->IsInstanceOf(jo->instance, c)) {
131
arg_expected = Variant::OBJECT;
132
} else {
133
//ok
134
}
135
} else {
136
arg_expected = Variant::OBJECT;
137
}
138
}
139
}
140
} break;
141
case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: {
142
if (p_args[i]->get_type() == Variant::ARRAY) {
143
Array arr = *p_args[i];
144
if (arr.is_typed() && arr.get_typed_builtin() != Variant::BOOL) {
145
arg_expected = Variant::ARRAY;
146
}
147
} else {
148
arg_expected = Variant::ARRAY;
149
}
150
} break;
151
case ARG_ARRAY_BIT | ARG_TYPE_BYTE:
152
case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
153
if (p_args[i]->get_type() != Variant::PACKED_BYTE_ARRAY) {
154
arg_expected = Variant::PACKED_BYTE_ARRAY;
155
}
156
} break;
157
case ARG_ARRAY_BIT | ARG_TYPE_SHORT:
158
case ARG_ARRAY_BIT | ARG_TYPE_INT: {
159
if (p_args[i]->get_type() == Variant::ARRAY) {
160
Array arr = *p_args[i];
161
if (arr.is_typed() && arr.get_typed_builtin() != Variant::INT) {
162
arg_expected = Variant::ARRAY;
163
}
164
} else if (p_args[i]->get_type() != Variant::PACKED_INT32_ARRAY) {
165
arg_expected = Variant::ARRAY;
166
}
167
} break;
168
case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
169
if (p_args[i]->get_type() == Variant::ARRAY) {
170
Array arr = *p_args[i];
171
if (arr.is_typed() && arr.get_typed_builtin() != Variant::INT) {
172
arg_expected = Variant::ARRAY;
173
}
174
} else if (p_args[i]->get_type() != Variant::PACKED_INT64_ARRAY) {
175
arg_expected = Variant::ARRAY;
176
}
177
} break;
178
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
179
if (p_args[i]->get_type() == Variant::ARRAY) {
180
Array arr = *p_args[i];
181
if (arr.is_typed() && arr.get_typed_builtin() != Variant::FLOAT) {
182
arg_expected = Variant::ARRAY;
183
}
184
} else if (p_args[i]->get_type() != Variant::PACKED_FLOAT32_ARRAY) {
185
arg_expected = Variant::ARRAY;
186
}
187
} break;
188
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
189
if (p_args[i]->get_type() == Variant::ARRAY) {
190
Array arr = *p_args[i];
191
if (arr.is_typed() && arr.get_typed_builtin() != Variant::FLOAT) {
192
arg_expected = Variant::ARRAY;
193
}
194
} else if (p_args[i]->get_type() != Variant::PACKED_FLOAT64_ARRAY) {
195
arg_expected = Variant::ARRAY;
196
}
197
} break;
198
case ARG_ARRAY_BIT | ARG_TYPE_STRING:
199
case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
200
if (p_args[i]->get_type() == Variant::ARRAY) {
201
Array arr = *p_args[i];
202
if (arr.is_typed() && arr.get_typed_builtin() != Variant::STRING) {
203
arg_expected = Variant::ARRAY;
204
}
205
} else if (p_args[i]->get_type() != Variant::PACKED_STRING_ARRAY) {
206
arg_expected = Variant::ARRAY;
207
}
208
} break;
209
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
210
if (p_args[i]->get_type() == Variant::ARRAY) {
211
Array arr = *p_args[i];
212
if (arr.is_typed() && arr.get_typed_builtin() != Variant::CALLABLE) {
213
arg_expected = Variant::ARRAY;
214
}
215
} else {
216
arg_expected = Variant::ARRAY;
217
}
218
} break;
219
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
220
if (p_args[i]->get_type() == Variant::ARRAY) {
221
Array arr = *p_args[i];
222
if (arr.is_typed() && arr.get_typed_builtin() != Variant::OBJECT) {
223
arg_expected = Variant::ARRAY;
224
} else {
225
String cn = E.param_sigs[i].operator String();
226
if (cn.begins_with("[L") && cn.ends_with(";")) {
227
cn = cn.substr(2, cn.length() - 3);
228
}
229
jclass c = jni_find_class(env, cn.utf8().get_data());
230
if (c) {
231
for (int j = 0; j < arr.size(); j++) {
232
Ref<JavaObject> jo = arr[j];
233
if (jo.is_valid()) {
234
if (!env->IsInstanceOf(jo->instance, c)) {
235
arg_expected = Variant::ARRAY;
236
break;
237
}
238
} else {
239
arg_expected = Variant::ARRAY;
240
break;
241
}
242
}
243
} else {
244
arg_expected = Variant::ARRAY;
245
}
246
}
247
} else {
248
arg_expected = Variant::ARRAY;
249
}
250
} break;
251
default: {
252
if (p_args[i]->get_type() != Variant::ARRAY) {
253
arg_expected = Variant::ARRAY;
254
}
255
} break;
256
}
257
258
if (arg_expected != Variant::NIL) {
259
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
260
r_error.argument = i;
261
r_error.expected = arg_expected;
262
valid = false;
263
break;
264
}
265
}
266
if (!valid) {
267
continue;
268
}
269
270
method = &E;
271
break;
272
}
273
274
if (!method) {
275
if (r_error.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
276
ERR_PRINT(vformat(R"(Cannot call static function "%s" on Java class "%s" directly. Make an instance instead.)", p_method, java_class_name));
277
}
278
return true; //no version convinces
279
}
280
281
r_error.error = Callable::CallError::CALL_OK;
282
283
jvalue *argv = nullptr;
284
285
if (method->param_types.size()) {
286
argv = (jvalue *)alloca(sizeof(jvalue) * method->param_types.size());
287
}
288
289
for (int i = 0; i < method->param_types.size(); i++) {
290
switch (method->param_types[i]) {
291
case ARG_TYPE_VOID: {
292
//can't happen
293
argv[i].l = nullptr; //I hope this works
294
} break;
295
296
case ARG_TYPE_BOOLEAN: {
297
argv[i].z = *p_args[i];
298
} break;
299
case ARG_TYPE_BYTE: {
300
argv[i].b = *p_args[i];
301
} break;
302
case ARG_TYPE_CHAR: {
303
argv[i].c = *p_args[i];
304
} break;
305
case ARG_TYPE_SHORT: {
306
argv[i].s = *p_args[i];
307
} break;
308
case ARG_TYPE_INT: {
309
argv[i].i = *p_args[i];
310
} break;
311
case ARG_TYPE_LONG: {
312
argv[i].j = (int64_t)*p_args[i];
313
} break;
314
case ARG_TYPE_FLOAT: {
315
argv[i].f = *p_args[i];
316
} break;
317
case ARG_TYPE_DOUBLE: {
318
argv[i].d = *p_args[i];
319
} break;
320
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BOOLEAN: {
321
jclass bclass = jni_find_class(env, "java/lang/Boolean");
322
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
323
jvalue val;
324
val.z = (bool)(*p_args[i]);
325
jobject obj = env->NewObjectA(bclass, ctor, &val);
326
argv[i].l = obj;
327
} break;
328
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BYTE: {
329
jclass bclass = jni_find_class(env, "java/lang/Byte");
330
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V");
331
jvalue val;
332
val.b = (int)(*p_args[i]);
333
jobject obj = env->NewObjectA(bclass, ctor, &val);
334
argv[i].l = obj;
335
} break;
336
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_CHAR: {
337
jclass bclass = jni_find_class(env, "java/lang/Character");
338
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V");
339
jvalue val;
340
val.c = (int)(*p_args[i]);
341
jobject obj = env->NewObjectA(bclass, ctor, &val);
342
argv[i].l = obj;
343
} break;
344
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_SHORT: {
345
jclass bclass = jni_find_class(env, "java/lang/Short");
346
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V");
347
jvalue val;
348
val.s = (int)(*p_args[i]);
349
jobject obj = env->NewObjectA(bclass, ctor, &val);
350
argv[i].l = obj;
351
} break;
352
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_INT: {
353
jclass bclass = jni_find_class(env, "java/lang/Integer");
354
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
355
jvalue val;
356
val.i = (int)(*p_args[i]);
357
jobject obj = env->NewObjectA(bclass, ctor, &val);
358
argv[i].l = obj;
359
} break;
360
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_LONG: {
361
jclass bclass = jni_find_class(env, "java/lang/Long");
362
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V");
363
jvalue val;
364
val.j = (int64_t)(*p_args[i]);
365
jobject obj = env->NewObjectA(bclass, ctor, &val);
366
argv[i].l = obj;
367
} break;
368
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_FLOAT: {
369
jclass bclass = jni_find_class(env, "java/lang/Float");
370
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V");
371
jvalue val;
372
val.f = (float)(*p_args[i]);
373
jobject obj = env->NewObjectA(bclass, ctor, &val);
374
argv[i].l = obj;
375
} break;
376
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_DOUBLE: {
377
jclass bclass = jni_find_class(env, "java/lang/Double");
378
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
379
jvalue val;
380
val.d = (double)(*p_args[i]);
381
jobject obj = env->NewObjectA(bclass, ctor, &val);
382
argv[i].l = obj;
383
} break;
384
case ARG_TYPE_STRING:
385
case ARG_TYPE_CHARSEQUENCE: {
386
String s = *p_args[i];
387
jstring jStr = env->NewStringUTF(s.utf8().get_data());
388
argv[i].l = jStr;
389
} break;
390
case ARG_TYPE_CALLABLE: {
391
jobject jcallable = callable_to_jcallable(env, *p_args[i]);
392
argv[i].l = jcallable;
393
} break;
394
case ARG_TYPE_CLASS: {
395
if (p_args[i]->get_type() == Variant::DICTIONARY) {
396
argv[i].l = _variant_to_jvalue(env, Variant::DICTIONARY, p_args[i]).l;
397
} else {
398
Ref<JavaObject> jo = *p_args[i];
399
if (jo.is_valid()) {
400
argv[i].l = jo->instance;
401
} else {
402
argv[i].l = nullptr; //I hope this works
403
}
404
}
405
} break;
406
case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: {
407
Array arr = *p_args[i];
408
jbooleanArray a = env->NewBooleanArray(arr.size());
409
for (int j = 0; j < arr.size(); j++) {
410
jboolean val = arr[j];
411
env->SetBooleanArrayRegion(a, j, 1, &val);
412
}
413
argv[i].l = a;
414
} break;
415
case ARG_ARRAY_BIT | ARG_TYPE_BYTE: {
416
jbyteArray a = nullptr;
417
418
if (p_args[i]->get_type() == Variant::ARRAY) {
419
Array arr = *p_args[i];
420
a = env->NewByteArray(arr.size());
421
for (int j = 0; j < arr.size(); j++) {
422
jbyte val = arr[j];
423
env->SetByteArrayRegion(a, j, 1, &val);
424
}
425
} else if (p_args[i]->get_type() == Variant::PACKED_BYTE_ARRAY) {
426
PackedByteArray arr = *p_args[i];
427
a = env->NewByteArray(arr.size());
428
env->SetByteArrayRegion(a, 0, arr.size(), (const jbyte *)arr.ptr());
429
}
430
431
argv[i].l = a;
432
} break;
433
case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
434
jcharArray a = nullptr;
435
436
if (p_args[i]->get_type() == Variant::ARRAY) {
437
Array arr = *p_args[i];
438
a = env->NewCharArray(arr.size());
439
for (int j = 0; j < arr.size(); j++) {
440
jchar val = arr[j];
441
env->SetCharArrayRegion(a, j, 1, &val);
442
}
443
} else if (p_args[i]->get_type() == Variant::PACKED_BYTE_ARRAY) {
444
PackedByteArray arr = *p_args[i];
445
// The data is expected to be UTF-16 encoded, so the length is half the size of the byte array.
446
int size = arr.size() / 2;
447
a = env->NewCharArray(size);
448
env->SetCharArrayRegion(a, 0, size, (const jchar *)arr.ptr());
449
}
450
451
argv[i].l = a;
452
453
} break;
454
case ARG_ARRAY_BIT | ARG_TYPE_SHORT: {
455
jshortArray a = nullptr;
456
457
if (p_args[i]->get_type() == Variant::ARRAY) {
458
Array arr = *p_args[i];
459
a = env->NewShortArray(arr.size());
460
for (int j = 0; j < arr.size(); j++) {
461
jshort val = arr[j];
462
env->SetShortArrayRegion(a, j, 1, &val);
463
}
464
} else if (p_args[i]->get_type() == Variant::PACKED_INT32_ARRAY) {
465
PackedInt32Array arr = *p_args[i];
466
a = env->NewShortArray(arr.size());
467
for (int j = 0; j < arr.size(); j++) {
468
jshort val = arr[j];
469
env->SetShortArrayRegion(a, j, 1, &val);
470
}
471
}
472
473
argv[i].l = a;
474
475
} break;
476
case ARG_ARRAY_BIT | ARG_TYPE_INT: {
477
jintArray a = nullptr;
478
479
if (p_args[i]->get_type() == Variant::ARRAY) {
480
Array arr = *p_args[i];
481
a = env->NewIntArray(arr.size());
482
for (int j = 0; j < arr.size(); j++) {
483
jint val = arr[j];
484
env->SetIntArrayRegion(a, j, 1, &val);
485
}
486
} else if (p_args[i]->get_type() == Variant::PACKED_INT32_ARRAY) {
487
PackedInt32Array arr = *p_args[i];
488
a = env->NewIntArray(arr.size());
489
env->SetIntArrayRegion(a, 0, arr.size(), arr.ptr());
490
}
491
492
argv[i].l = a;
493
} break;
494
case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
495
jlongArray a = nullptr;
496
497
if (p_args[i]->get_type() == Variant::ARRAY) {
498
Array arr = *p_args[i];
499
a = env->NewLongArray(arr.size());
500
for (int j = 0; j < arr.size(); j++) {
501
jlong val = (int64_t)arr[j];
502
env->SetLongArrayRegion(a, j, 1, &val);
503
}
504
} else if (p_args[i]->get_type() == Variant::PACKED_INT64_ARRAY) {
505
PackedInt64Array arr = *p_args[i];
506
a = env->NewLongArray(arr.size());
507
env->SetLongArrayRegion(a, 0, arr.size(), arr.ptr());
508
}
509
510
argv[i].l = a;
511
} break;
512
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
513
jfloatArray a = nullptr;
514
515
if (p_args[i]->get_type() == Variant::ARRAY) {
516
Array arr = *p_args[i];
517
a = env->NewFloatArray(arr.size());
518
for (int j = 0; j < arr.size(); j++) {
519
jfloat val = arr[j];
520
env->SetFloatArrayRegion(a, j, 1, &val);
521
}
522
} else if (p_args[i]->get_type() == Variant::PACKED_FLOAT32_ARRAY) {
523
PackedFloat32Array arr = *p_args[i];
524
a = env->NewFloatArray(arr.size());
525
env->SetFloatArrayRegion(a, 0, arr.size(), arr.ptr());
526
}
527
528
argv[i].l = a;
529
} break;
530
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
531
jdoubleArray a = nullptr;
532
533
if (p_args[i]->get_type() == Variant::ARRAY) {
534
Array arr = *p_args[i];
535
a = env->NewDoubleArray(arr.size());
536
for (int j = 0; j < arr.size(); j++) {
537
jdouble val = arr[j];
538
env->SetDoubleArrayRegion(a, j, 1, &val);
539
}
540
} else if (p_args[i]->get_type() == Variant::PACKED_FLOAT64_ARRAY) {
541
PackedFloat64Array arr = *p_args[i];
542
a = env->NewDoubleArray(arr.size());
543
env->SetDoubleArrayRegion(a, 0, arr.size(), arr.ptr());
544
}
545
546
argv[i].l = a;
547
} break;
548
case ARG_ARRAY_BIT | ARG_TYPE_STRING:
549
case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
550
jobjectArray a = nullptr;
551
552
if (p_args[i]->get_type() == Variant::ARRAY) {
553
Array arr = *p_args[i];
554
a = env->NewObjectArray(arr.size(), jni_find_class(env, "java/lang/String"), nullptr);
555
for (int j = 0; j < arr.size(); j++) {
556
String s = arr[j];
557
jstring jStr = env->NewStringUTF(s.utf8().get_data());
558
env->SetObjectArrayElement(a, j, jStr);
559
}
560
} else if (p_args[i]->get_type() == Variant::PACKED_STRING_ARRAY) {
561
PackedStringArray arr = *p_args[i];
562
a = env->NewObjectArray(arr.size(), jni_find_class(env, "java/lang/String"), nullptr);
563
for (int j = 0; j < arr.size(); j++) {
564
String s = arr[j];
565
jstring jStr = env->NewStringUTF(s.utf8().get_data());
566
env->SetObjectArrayElement(a, j, jStr);
567
}
568
}
569
570
argv[i].l = a;
571
} break;
572
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
573
Array arr = *p_args[i];
574
jobjectArray jarr = env->NewObjectArray(arr.size(), jni_find_class(env, "org/godotengine/godot/variant/Callable"), nullptr);
575
for (int j = 0; j < arr.size(); j++) {
576
Variant callable = arr[j];
577
jobject jcallable = callable_to_jcallable(env, callable);
578
env->SetObjectArrayElement(jarr, j, jcallable);
579
}
580
581
argv[i].l = jarr;
582
} break;
583
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
584
String cn = method->param_sigs[i].operator String();
585
if (cn.begins_with("[L") && cn.ends_with(";")) {
586
cn = cn.substr(2, cn.length() - 3);
587
}
588
jclass c = jni_find_class(env, cn.utf8().get_data());
589
if (c) {
590
Array arr = *p_args[i];
591
jobjectArray jarr = env->NewObjectArray(arr.size(), c, nullptr);
592
for (int j = 0; j < arr.size(); j++) {
593
Ref<JavaObject> jo = arr[j];
594
env->SetObjectArrayElement(jarr, j, jo->instance);
595
}
596
597
argv[i].l = jarr;
598
}
599
} break;
600
}
601
}
602
603
r_error.error = Callable::CallError::CALL_OK;
604
bool success = true;
605
606
switch (method->return_type) {
607
case ARG_TYPE_VOID: {
608
if (method->_static) {
609
env->CallStaticVoidMethodA(_class, method->method, argv);
610
} else {
611
env->CallVoidMethodA(p_instance->instance, method->method, argv);
612
}
613
ret = Variant();
614
615
} break;
616
case ARG_TYPE_BOOLEAN: {
617
if (method->_static) {
618
ret = env->CallStaticBooleanMethodA(_class, method->method, argv);
619
} else {
620
ret = env->CallBooleanMethodA(p_instance->instance, method->method, argv);
621
}
622
} break;
623
case ARG_TYPE_BYTE: {
624
if (method->_static) {
625
ret = env->CallStaticByteMethodA(_class, method->method, argv);
626
} else {
627
ret = env->CallByteMethodA(p_instance->instance, method->method, argv);
628
}
629
} break;
630
case ARG_TYPE_CHAR: {
631
if (method->_static) {
632
ret = env->CallStaticCharMethodA(_class, method->method, argv);
633
} else {
634
ret = env->CallCharMethodA(p_instance->instance, method->method, argv);
635
}
636
} break;
637
case ARG_TYPE_SHORT: {
638
if (method->_static) {
639
ret = env->CallStaticShortMethodA(_class, method->method, argv);
640
} else {
641
ret = env->CallShortMethodA(p_instance->instance, method->method, argv);
642
}
643
644
} break;
645
case ARG_TYPE_INT: {
646
if (method->_static) {
647
ret = env->CallStaticIntMethodA(_class, method->method, argv);
648
} else {
649
ret = env->CallIntMethodA(p_instance->instance, method->method, argv);
650
}
651
652
} break;
653
case ARG_TYPE_LONG: {
654
if (method->_static) {
655
ret = (int64_t)env->CallStaticLongMethodA(_class, method->method, argv);
656
} else {
657
ret = (int64_t)env->CallLongMethodA(p_instance->instance, method->method, argv);
658
}
659
660
} break;
661
case ARG_TYPE_FLOAT: {
662
if (method->_static) {
663
ret = env->CallStaticFloatMethodA(_class, method->method, argv);
664
} else {
665
ret = env->CallFloatMethodA(p_instance->instance, method->method, argv);
666
}
667
668
} break;
669
case ARG_TYPE_DOUBLE: {
670
if (method->_static) {
671
ret = env->CallStaticDoubleMethodA(_class, method->method, argv);
672
} else {
673
ret = env->CallDoubleMethodA(p_instance->instance, method->method, argv);
674
}
675
676
} break;
677
default: {
678
jobject obj;
679
if (method->_constructor) {
680
obj = env->NewObjectA(_class, method->method, argv);
681
} else if (method->_static) {
682
obj = env->CallStaticObjectMethodA(_class, method->method, argv);
683
} else {
684
obj = env->CallObjectMethodA(p_instance->instance, method->method, argv);
685
}
686
687
if (!obj) {
688
ret = Variant();
689
} else {
690
if (!_convert_object_to_variant(env, obj, ret, method->return_type)) {
691
ret = Variant();
692
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
693
success = false;
694
}
695
}
696
697
} break;
698
}
699
700
jobject exception = env->ExceptionOccurred();
701
if (exception) {
702
env->ExceptionClear();
703
704
jclass java_class = env->GetObjectClass(exception);
705
Ref<JavaClass> java_class_wrapped = JavaClassWrapper::singleton->wrap_jclass(java_class);
706
707
JavaClassWrapper::singleton->exception.instantiate(java_class_wrapped, exception);
708
} else {
709
JavaClassWrapper::singleton->exception.unref();
710
}
711
712
env->PopLocalFrame(nullptr);
713
714
return success;
715
}
716
717
bool JavaClass::_get(const StringName &p_name, Variant &r_ret) const {
718
if (constant_map.has(p_name)) {
719
r_ret = constant_map[p_name];
720
return true;
721
}
722
723
return false;
724
}
725
726
Variant JavaClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
727
// Godot methods take precedence.
728
Variant ret = RefCounted::callp(p_method, p_args, p_argcount, r_error);
729
if (r_error.error == Callable::CallError::CALL_OK) {
730
return ret;
731
}
732
733
String method = (p_method == java_constructor_name) ? "<init>" : p_method;
734
bool found = _call_method(nullptr, method, p_args, p_argcount, r_error, ret);
735
if (found) {
736
return ret;
737
}
738
739
return Variant();
740
}
741
742
String JavaClass::get_java_class_name() const {
743
return java_class_name;
744
}
745
746
TypedArray<Dictionary> JavaClass::get_java_method_list() const {
747
TypedArray<Dictionary> method_list;
748
749
for (const KeyValue<StringName, List<MethodInfo>> &item : methods) {
750
for (const MethodInfo &mi : item.value) {
751
Dictionary method;
752
753
method["name"] = mi._constructor ? java_constructor_name : String(item.key);
754
method["id"] = (uint64_t)mi.method;
755
method["default_args"] = Array();
756
method["flags"] = METHOD_FLAGS_DEFAULT & (mi._static || mi._constructor ? METHOD_FLAG_STATIC : METHOD_FLAG_NORMAL);
757
758
{
759
Array a;
760
761
for (uint32_t argtype : mi.param_types) {
762
Dictionary d;
763
764
Variant::Type t = Variant::NIL;
765
float likelihood = 0.0;
766
_convert_to_variant_type(argtype, t, likelihood);
767
d["type"] = t;
768
if (t == Variant::OBJECT) {
769
d["hint"] = PROPERTY_HINT_RESOURCE_TYPE;
770
d["hint_string"] = "JavaObject";
771
} else {
772
d["hint"] = 0;
773
d["hint_string"] = "";
774
}
775
776
a.push_back(d);
777
}
778
779
method["args"] = a;
780
}
781
782
{
783
Dictionary d;
784
785
if (mi._constructor) {
786
d["type"] = Variant::OBJECT;
787
d["hint"] = PROPERTY_HINT_RESOURCE_TYPE;
788
d["hint_string"] = "JavaObject";
789
} else {
790
Variant::Type t = Variant::NIL;
791
float likelihood = 0.0;
792
_convert_to_variant_type(mi.return_type, t, likelihood);
793
d["type"] = t;
794
if (t == Variant::OBJECT) {
795
d["hint"] = PROPERTY_HINT_RESOURCE_TYPE;
796
d["hint_string"] = "JavaObject";
797
} else {
798
d["hint"] = 0;
799
d["hint_string"] = "";
800
}
801
}
802
803
method["return_type"] = d;
804
}
805
806
method_list.push_back(method);
807
}
808
}
809
810
return method_list;
811
}
812
813
Ref<JavaClass> JavaClass::get_java_parent_class() const {
814
ERR_FAIL_NULL_V(_class, Ref<JavaClass>());
815
816
JNIEnv *env = get_jni_env();
817
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
818
819
jclass superclass = (jclass)env->CallObjectMethod(_class, JavaClassWrapper::singleton->Class_getSuperclass);
820
if (!superclass) {
821
return Ref<JavaClass>();
822
}
823
824
Ref<JavaClass> ret = JavaClassWrapper::singleton->wrap_jclass(superclass);
825
env->DeleteLocalRef(superclass);
826
return ret;
827
}
828
829
String JavaClass::to_string() {
830
return "<JavaClass:" + java_class_name + ">";
831
}
832
833
bool JavaClass::has_java_method(const StringName &p_method) const {
834
String method = (p_method == java_constructor_name) ? "<init>" : p_method;
835
return methods.has(method);
836
}
837
838
JavaClass::JavaClass() {
839
}
840
841
JavaClass::~JavaClass() {
842
if (_class) {
843
JNIEnv *env = get_jni_env();
844
ERR_FAIL_NULL(env);
845
846
env->DeleteGlobalRef(_class);
847
}
848
}
849
850
/////////////////////
851
852
Variant JavaObject::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
853
// Godot methods take precedence.
854
Variant ret = RefCounted::callp(p_method, p_args, p_argcount, r_error);
855
if (r_error.error == Callable::CallError::CALL_OK) {
856
return ret;
857
}
858
859
if (instance) {
860
Ref<JavaClass> c = base_class;
861
while (c.is_valid()) {
862
bool found = c->_call_method(this, p_method, p_args, p_argcount, r_error, ret);
863
if (found) {
864
return ret;
865
}
866
c = c->get_java_parent_class();
867
}
868
}
869
870
return Variant();
871
}
872
873
Ref<JavaClass> JavaObject::get_java_class() const {
874
return base_class;
875
}
876
877
String JavaObject::to_string() {
878
if (base_class.is_valid() && instance) {
879
return "<JavaObject:" + base_class->java_class_name + " \"" + (String)call("toString") + "\">";
880
}
881
return RefCounted::to_string();
882
}
883
884
bool JavaObject::has_java_method(const StringName &p_method) const {
885
if (instance) {
886
Ref<JavaClass> c = base_class;
887
while (c.is_valid()) {
888
if (c->has_java_method(p_method)) {
889
return true;
890
}
891
c = c->get_java_parent_class();
892
}
893
}
894
return false;
895
}
896
897
JavaObject::JavaObject() {
898
}
899
900
JavaObject::JavaObject(const Ref<JavaClass> &p_base, jobject p_instance) {
901
JNIEnv *env = get_jni_env();
902
ERR_FAIL_NULL(env);
903
904
base_class = p_base;
905
instance = env->NewGlobalRef(p_instance);
906
}
907
908
JavaObject::~JavaObject() {
909
if (instance) {
910
JNIEnv *env = get_jni_env();
911
ERR_FAIL_NULL(env);
912
913
env->DeleteGlobalRef(instance);
914
}
915
}
916
917
////////////////////
918
919
bool JavaClassWrapper::_get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig) {
920
jstring name2 = (jstring)env->CallObjectMethod(obj, Class_getName);
921
String str_type = jstring_to_string(name2, env);
922
env->DeleteLocalRef(name2);
923
uint32_t t = 0;
924
925
if (str_type.begins_with("[")) {
926
t = JavaClass::ARG_ARRAY_BIT;
927
strsig = "[";
928
str_type = str_type.substr(1);
929
if (str_type.begins_with("[")) {
930
print_line("Nested arrays not supported for type: " + str_type);
931
return false;
932
}
933
if (str_type.begins_with("L")) {
934
str_type = str_type.substr(1, str_type.length() - 2); //ok it's a class
935
}
936
}
937
938
if (str_type == "void" || str_type == "V") {
939
t |= JavaClass::ARG_TYPE_VOID;
940
strsig += "V";
941
} else if (str_type == "boolean" || str_type == "Z") {
942
t |= JavaClass::ARG_TYPE_BOOLEAN;
943
strsig += "Z";
944
} else if (str_type == "byte" || str_type == "B") {
945
t |= JavaClass::ARG_TYPE_BYTE;
946
strsig += "B";
947
} else if (str_type == "char" || str_type == "C") {
948
t |= JavaClass::ARG_TYPE_CHAR;
949
strsig += "C";
950
} else if (str_type == "short" || str_type == "S") {
951
t |= JavaClass::ARG_TYPE_SHORT;
952
strsig += "S";
953
} else if (str_type == "int" || str_type == "I") {
954
t |= JavaClass::ARG_TYPE_INT;
955
strsig += "I";
956
} else if (str_type == "long" || str_type == "J") {
957
t |= JavaClass::ARG_TYPE_LONG;
958
strsig += "J";
959
} else if (str_type == "float" || str_type == "F") {
960
t |= JavaClass::ARG_TYPE_FLOAT;
961
strsig += "F";
962
} else if (str_type == "double" || str_type == "D") {
963
t |= JavaClass::ARG_TYPE_DOUBLE;
964
strsig += "D";
965
} else if (str_type == "java.lang.String") {
966
t |= JavaClass::ARG_TYPE_STRING;
967
strsig += "Ljava/lang/String;";
968
} else if (str_type == "java.lang.CharSequence") {
969
t |= JavaClass::ARG_TYPE_CHARSEQUENCE;
970
strsig += "Ljava/lang/CharSequence;";
971
} else if (str_type == "org.godotengine.godot.variant.Callable") {
972
t |= JavaClass::ARG_TYPE_CALLABLE;
973
strsig += "Lorg/godotengine/godot/variant/Callable;";
974
} else if (str_type == "java.lang.Boolean") {
975
t |= JavaClass::ARG_TYPE_BOOLEAN | JavaClass::ARG_NUMBER_CLASS_BIT;
976
strsig += "Ljava/lang/Boolean;";
977
} else if (str_type == "java.lang.Byte") {
978
t |= JavaClass::ARG_TYPE_BYTE | JavaClass::ARG_NUMBER_CLASS_BIT;
979
strsig += "Ljava/lang/Byte;";
980
} else if (str_type == "java.lang.Character") {
981
t |= JavaClass::ARG_TYPE_CHAR | JavaClass::ARG_NUMBER_CLASS_BIT;
982
strsig += "Ljava/lang/Character;";
983
} else if (str_type == "java.lang.Short") {
984
t |= JavaClass::ARG_TYPE_SHORT | JavaClass::ARG_NUMBER_CLASS_BIT;
985
strsig += "Ljava/lang/Short;";
986
} else if (str_type == "java.lang.Integer") {
987
t |= JavaClass::ARG_TYPE_INT | JavaClass::ARG_NUMBER_CLASS_BIT;
988
strsig += "Ljava/lang/Integer;";
989
} else if (str_type == "java.lang.Long") {
990
t |= JavaClass::ARG_TYPE_LONG | JavaClass::ARG_NUMBER_CLASS_BIT;
991
strsig += "Ljava/lang/Long;";
992
} else if (str_type == "java.lang.Float") {
993
t |= JavaClass::ARG_TYPE_FLOAT | JavaClass::ARG_NUMBER_CLASS_BIT;
994
strsig += "Ljava/lang/Float;";
995
} else if (str_type == "java.lang.Double") {
996
t |= JavaClass::ARG_TYPE_DOUBLE | JavaClass::ARG_NUMBER_CLASS_BIT;
997
strsig += "Ljava/lang/Double;";
998
} else {
999
//a class likely
1000
strsig += "L" + str_type.replace_char('.', '/') + ";";
1001
t |= JavaClass::ARG_TYPE_CLASS;
1002
}
1003
1004
sig = t;
1005
1006
return true;
1007
}
1008
1009
bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &var, uint32_t p_sig) {
1010
if (!obj) {
1011
var = Variant(); //seems null is just null...
1012
return true;
1013
}
1014
1015
switch (p_sig) {
1016
case ARG_TYPE_VOID: {
1017
return Variant();
1018
} break;
1019
case ARG_TYPE_BOOLEAN | ARG_NUMBER_CLASS_BIT: {
1020
var = env->CallBooleanMethod(obj, JavaClassWrapper::singleton->Boolean_booleanValue);
1021
return true;
1022
} break;
1023
case ARG_TYPE_BYTE | ARG_NUMBER_CLASS_BIT: {
1024
var = env->CallByteMethod(obj, JavaClassWrapper::singleton->Byte_byteValue);
1025
return true;
1026
1027
} break;
1028
case ARG_TYPE_CHAR | ARG_NUMBER_CLASS_BIT: {
1029
var = env->CallCharMethod(obj, JavaClassWrapper::singleton->Character_characterValue);
1030
return true;
1031
1032
} break;
1033
case ARG_TYPE_SHORT | ARG_NUMBER_CLASS_BIT: {
1034
var = env->CallShortMethod(obj, JavaClassWrapper::singleton->Short_shortValue);
1035
return true;
1036
1037
} break;
1038
case ARG_TYPE_INT | ARG_NUMBER_CLASS_BIT: {
1039
var = env->CallIntMethod(obj, JavaClassWrapper::singleton->Integer_integerValue);
1040
return true;
1041
1042
} break;
1043
case ARG_TYPE_LONG | ARG_NUMBER_CLASS_BIT: {
1044
var = (int64_t)env->CallLongMethod(obj, JavaClassWrapper::singleton->Long_longValue);
1045
return true;
1046
1047
} break;
1048
case ARG_TYPE_FLOAT | ARG_NUMBER_CLASS_BIT: {
1049
var = env->CallFloatMethod(obj, JavaClassWrapper::singleton->Float_floatValue);
1050
return true;
1051
1052
} break;
1053
case ARG_TYPE_DOUBLE | ARG_NUMBER_CLASS_BIT: {
1054
var = env->CallDoubleMethod(obj, JavaClassWrapper::singleton->Double_doubleValue);
1055
return true;
1056
} break;
1057
case ARG_TYPE_STRING: {
1058
var = jstring_to_string((jstring)obj, env);
1059
return true;
1060
} break;
1061
case ARG_TYPE_CHARSEQUENCE: {
1062
var = charsequence_to_string(env, obj);
1063
return true;
1064
} break;
1065
case ARG_TYPE_CALLABLE: {
1066
var = jcallable_to_callable(env, obj);
1067
return true;
1068
} break;
1069
case ARG_TYPE_CLASS: {
1070
jclass java_class = env->GetObjectClass(obj);
1071
Ref<JavaClass> java_class_wrapped = JavaClassWrapper::singleton->wrap_jclass(java_class);
1072
env->DeleteLocalRef(java_class);
1073
1074
if (java_class_wrapped.is_valid()) {
1075
String cn = java_class_wrapped->get_java_class_name();
1076
if (cn == "org.godotengine.godot.Dictionary" || cn == "java.util.HashMap") {
1077
var = _jobject_to_variant(env, obj);
1078
} else {
1079
Ref<JavaObject> ret = Ref<JavaObject>(memnew(JavaObject(java_class_wrapped, obj)));
1080
var = ret;
1081
}
1082
return true;
1083
}
1084
1085
return false;
1086
} break;
1087
case ARG_ARRAY_BIT | ARG_TYPE_VOID: {
1088
var = Array(); // ?
1089
return true;
1090
} break;
1091
case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: {
1092
Array ret;
1093
jobjectArray arr = (jobjectArray)obj;
1094
1095
int count = env->GetArrayLength(arr);
1096
ret.resize(count);
1097
1098
for (int i = 0; i < count; i++) {
1099
jboolean val;
1100
env->GetBooleanArrayRegion((jbooleanArray)arr, i, 1, &val);
1101
ret[i] = (bool)val;
1102
}
1103
1104
var = ret;
1105
return true;
1106
1107
} break;
1108
case ARG_ARRAY_BIT | ARG_TYPE_BYTE: {
1109
PackedByteArray ret;
1110
jobjectArray arr = (jobjectArray)obj;
1111
1112
int count = env->GetArrayLength(arr);
1113
ret.resize(count);
1114
env->GetByteArrayRegion((jbyteArray)arr, 0, count, (int8_t *)ret.ptrw());
1115
1116
var = ret;
1117
return true;
1118
} break;
1119
case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
1120
PackedByteArray ret;
1121
jobjectArray arr = (jobjectArray)obj;
1122
1123
int count = env->GetArrayLength(arr);
1124
// Char arrays are UTF-16 encoded, so it's double the length.
1125
ret.resize(count * 2);
1126
env->GetCharArrayRegion((jcharArray)arr, 0, count, (jchar *)ret.ptrw());
1127
1128
var = ret;
1129
return true;
1130
} break;
1131
case ARG_ARRAY_BIT | ARG_TYPE_SHORT: {
1132
PackedInt32Array ret;
1133
jobjectArray arr = (jobjectArray)obj;
1134
1135
int count = env->GetArrayLength(arr);
1136
ret.resize(count);
1137
1138
int32_t *ptr = ret.ptrw();
1139
for (int i = 0; i < count; i++) {
1140
jshort val;
1141
env->GetShortArrayRegion((jshortArray)arr, i, 1, &val);
1142
ptr[i] = val;
1143
}
1144
1145
var = ret;
1146
return true;
1147
} break;
1148
case ARG_ARRAY_BIT | ARG_TYPE_INT: {
1149
PackedInt32Array ret;
1150
jobjectArray arr = (jobjectArray)obj;
1151
1152
int count = env->GetArrayLength(arr);
1153
ret.resize(count);
1154
env->GetIntArrayRegion((jintArray)arr, 0, count, ret.ptrw());
1155
1156
var = ret;
1157
return true;
1158
} break;
1159
case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
1160
PackedInt64Array ret;
1161
jobjectArray arr = (jobjectArray)obj;
1162
1163
int count = env->GetArrayLength(arr);
1164
ret.resize(count);
1165
env->GetLongArrayRegion((jlongArray)arr, 0, count, ret.ptrw());
1166
1167
var = ret;
1168
return true;
1169
} break;
1170
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
1171
PackedFloat32Array ret;
1172
jobjectArray arr = (jobjectArray)obj;
1173
1174
int count = env->GetArrayLength(arr);
1175
ret.resize(count);
1176
env->GetFloatArrayRegion((jfloatArray)arr, 0, count, ret.ptrw());
1177
1178
var = ret;
1179
return true;
1180
} break;
1181
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
1182
PackedFloat64Array ret;
1183
jobjectArray arr = (jobjectArray)obj;
1184
1185
int count = env->GetArrayLength(arr);
1186
ret.resize(count);
1187
env->GetDoubleArrayRegion((jdoubleArray)arr, 0, count, ret.ptrw());
1188
1189
var = ret;
1190
return true;
1191
} break;
1192
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: {
1193
Array ret;
1194
jobjectArray arr = (jobjectArray)obj;
1195
1196
int count = env->GetArrayLength(arr);
1197
ret.resize(count);
1198
1199
for (int i = 0; i < count; i++) {
1200
jobject o = env->GetObjectArrayElement(arr, i);
1201
if (o) {
1202
bool val = env->CallBooleanMethod(o, JavaClassWrapper::singleton->Boolean_booleanValue);
1203
ret[i] = val;
1204
}
1205
env->DeleteLocalRef(o);
1206
}
1207
1208
var = ret;
1209
return true;
1210
1211
} break;
1212
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_BYTE: {
1213
PackedByteArray ret;
1214
jobjectArray arr = (jobjectArray)obj;
1215
1216
int count = env->GetArrayLength(arr);
1217
ret.resize(count);
1218
1219
uint8_t *ptr = ret.ptrw();
1220
for (int i = 0; i < count; i++) {
1221
jobject o = env->GetObjectArrayElement(arr, i);
1222
if (!o) {
1223
ptr[i] = 0;
1224
} else {
1225
int val = env->CallByteMethod(o, JavaClassWrapper::singleton->Byte_byteValue);
1226
ptr[i] = (uint8_t)val;
1227
}
1228
env->DeleteLocalRef(o);
1229
}
1230
1231
var = ret;
1232
return true;
1233
} break;
1234
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
1235
PackedByteArray ret;
1236
jobjectArray arr = (jobjectArray)obj;
1237
1238
int count = env->GetArrayLength(arr);
1239
// Char arrays are UTF-16 encoded, so it's double the length.
1240
ret.resize(count * 2);
1241
1242
jchar *ptr = (jchar *)ret.ptrw();
1243
for (int i = 0; i < count; i++) {
1244
jobject o = env->GetObjectArrayElement(arr, i);
1245
if (!o) {
1246
count = i;
1247
break;
1248
} else {
1249
int val = env->CallCharMethod(o, JavaClassWrapper::singleton->Character_characterValue);
1250
ptr[i] = (jchar)val;
1251
}
1252
env->DeleteLocalRef(o);
1253
}
1254
1255
var = ret;
1256
return true;
1257
} break;
1258
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_SHORT: {
1259
PackedInt32Array ret;
1260
jobjectArray arr = (jobjectArray)obj;
1261
1262
int count = env->GetArrayLength(arr);
1263
ret.resize(count);
1264
1265
int32_t *ptr = ret.ptrw();
1266
for (int i = 0; i < count; i++) {
1267
jobject o = env->GetObjectArrayElement(arr, i);
1268
if (!o) {
1269
ptr[i] = 0;
1270
} else {
1271
int val = env->CallShortMethod(o, JavaClassWrapper::singleton->Short_shortValue);
1272
ptr[i] = val;
1273
}
1274
env->DeleteLocalRef(o);
1275
}
1276
1277
var = ret;
1278
return true;
1279
} break;
1280
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_INT: {
1281
PackedInt32Array ret;
1282
jobjectArray arr = (jobjectArray)obj;
1283
1284
int count = env->GetArrayLength(arr);
1285
ret.resize(count);
1286
1287
int32_t *ptr = ret.ptrw();
1288
for (int i = 0; i < count; i++) {
1289
jobject o = env->GetObjectArrayElement(arr, i);
1290
if (!o) {
1291
ptr[i] = 0;
1292
} else {
1293
int val = env->CallIntMethod(o, JavaClassWrapper::singleton->Integer_integerValue);
1294
ptr[i] = val;
1295
}
1296
env->DeleteLocalRef(o);
1297
}
1298
1299
var = ret;
1300
return true;
1301
} break;
1302
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_LONG: {
1303
PackedInt64Array ret;
1304
jobjectArray arr = (jobjectArray)obj;
1305
1306
int count = env->GetArrayLength(arr);
1307
ret.resize(count);
1308
1309
int64_t *ptr = ret.ptrw();
1310
for (int i = 0; i < count; i++) {
1311
jobject o = env->GetObjectArrayElement(arr, i);
1312
if (!o) {
1313
ptr[i] = 0;
1314
} else {
1315
int64_t val = env->CallLongMethod(o, JavaClassWrapper::singleton->Long_longValue);
1316
ptr[i] = val;
1317
}
1318
env->DeleteLocalRef(o);
1319
}
1320
1321
var = ret;
1322
return true;
1323
} break;
1324
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
1325
PackedFloat32Array ret;
1326
jobjectArray arr = (jobjectArray)obj;
1327
1328
int count = env->GetArrayLength(arr);
1329
ret.resize(count);
1330
1331
float *ptr = ret.ptrw();
1332
for (int i = 0; i < count; i++) {
1333
jobject o = env->GetObjectArrayElement(arr, i);
1334
if (!o) {
1335
ptr[i] = 0.0;
1336
} else {
1337
float val = env->CallFloatMethod(o, JavaClassWrapper::singleton->Float_floatValue);
1338
ptr[i] = val;
1339
}
1340
env->DeleteLocalRef(o);
1341
}
1342
1343
var = ret;
1344
return true;
1345
} break;
1346
case ARG_NUMBER_CLASS_BIT | ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
1347
PackedFloat64Array ret;
1348
jobjectArray arr = (jobjectArray)obj;
1349
1350
int count = env->GetArrayLength(arr);
1351
ret.resize(count);
1352
1353
double *ptr = ret.ptrw();
1354
for (int i = 0; i < count; i++) {
1355
jobject o = env->GetObjectArrayElement(arr, i);
1356
if (!o) {
1357
ptr[i] = 0.0;
1358
} else {
1359
double val = env->CallDoubleMethod(o, JavaClassWrapper::singleton->Double_doubleValue);
1360
ptr[i] = val;
1361
}
1362
env->DeleteLocalRef(o);
1363
}
1364
1365
var = ret;
1366
return true;
1367
} break;
1368
1369
case ARG_ARRAY_BIT | ARG_TYPE_STRING: {
1370
PackedStringArray ret;
1371
jobjectArray arr = (jobjectArray)obj;
1372
1373
int count = env->GetArrayLength(arr);
1374
ret.resize(count);
1375
1376
String *ptr = ret.ptrw();
1377
for (int i = 0; i < count; i++) {
1378
jobject o = env->GetObjectArrayElement(arr, i);
1379
if (o) {
1380
String val = jstring_to_string((jstring)o, env);
1381
ptr[i] = val;
1382
}
1383
env->DeleteLocalRef(o);
1384
}
1385
1386
var = ret;
1387
return true;
1388
} break;
1389
case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
1390
PackedStringArray ret;
1391
jobjectArray arr = (jobjectArray)obj;
1392
1393
int count = env->GetArrayLength(arr);
1394
ret.resize(count);
1395
1396
String *ptr = ret.ptrw();
1397
for (int i = 0; i < count; i++) {
1398
jobject o = env->GetObjectArrayElement(arr, i);
1399
if (o) {
1400
String val = charsequence_to_string(env, o);
1401
ptr[i] = val;
1402
}
1403
env->DeleteLocalRef(o);
1404
}
1405
1406
var = ret;
1407
return true;
1408
} break;
1409
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
1410
Array ret;
1411
jobjectArray jarr = (jobjectArray)obj;
1412
int count = env->GetArrayLength(jarr);
1413
ret.resize(count);
1414
for (int i = 0; i < count; i++) {
1415
jobject o = env->GetObjectArrayElement(jarr, i);
1416
if (o) {
1417
Callable callable = jcallable_to_callable(env, o);
1418
ret[i] = callable;
1419
}
1420
env->DeleteLocalRef(o);
1421
}
1422
1423
var = ret;
1424
return true;
1425
} break;
1426
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
1427
Array ret;
1428
jobjectArray jarr = (jobjectArray)obj;
1429
int count = env->GetArrayLength(jarr);
1430
ret.resize(count);
1431
for (int i = 0; i < count; i++) {
1432
jobject obj = env->GetObjectArrayElement(jarr, i);
1433
if (obj) {
1434
jclass java_class = env->GetObjectClass(obj);
1435
Ref<JavaClass> java_class_wrapped = JavaClassWrapper::singleton->wrap_jclass(java_class);
1436
env->DeleteLocalRef(java_class);
1437
1438
if (java_class_wrapped.is_valid()) {
1439
String cn = java_class_wrapped->get_java_class_name();
1440
if (cn == "org.godotengine.godot.Dictionary" || cn == "java.util.HashMap") {
1441
ret[i] = _jobject_to_variant(env, obj);
1442
} else {
1443
Ref<JavaObject> java_obj_wrapped = Ref<JavaObject>(memnew(JavaObject(java_class_wrapped, obj)));
1444
ret[i] = java_obj_wrapped;
1445
}
1446
}
1447
}
1448
env->DeleteLocalRef(obj);
1449
}
1450
1451
var = ret;
1452
return true;
1453
} break;
1454
}
1455
1456
return false;
1457
}
1458
1459
Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_public_methods_access) {
1460
String class_name_dots = p_class.replace_char('/', '.');
1461
if (class_cache.has(class_name_dots)) {
1462
return class_cache[class_name_dots];
1463
}
1464
1465
JNIEnv *env = get_jni_env();
1466
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
1467
1468
jclass bclass = jni_find_class(env, class_name_dots.replace_char('.', '/').utf8().get_data());
1469
ERR_FAIL_NULL_V_MSG(bclass, Ref<JavaClass>(), vformat("Java class '%s' not found.", p_class));
1470
1471
jobjectArray constructors = (jobjectArray)env->CallObjectMethod(bclass, Class_getConstructors);
1472
if (env->ExceptionCheck()) {
1473
env->ExceptionDescribe();
1474
env->ExceptionClear();
1475
}
1476
ERR_FAIL_NULL_V(constructors, Ref<JavaClass>());
1477
1478
jobjectArray methods = (jobjectArray)env->CallObjectMethod(bclass, Class_getDeclaredMethods);
1479
if (env->ExceptionCheck()) {
1480
env->ExceptionDescribe();
1481
env->ExceptionClear();
1482
}
1483
ERR_FAIL_NULL_V(methods, Ref<JavaClass>());
1484
1485
Ref<JavaClass> java_class = memnew(JavaClass);
1486
java_class->java_class_name = class_name_dots;
1487
Vector<String> class_name_parts = class_name_dots.split(".");
1488
java_class->java_constructor_name = class_name_parts[class_name_parts.size() - 1];
1489
java_class->_class = (jclass)env->NewGlobalRef(bclass);
1490
class_cache[class_name_dots] = java_class;
1491
1492
int constructor_count = env->GetArrayLength(constructors);
1493
int method_count = env->GetArrayLength(methods);
1494
1495
int methods_and_constructors_count = method_count + constructor_count;
1496
for (int i = 0; i < methods_and_constructors_count; i++) {
1497
bool is_constructor = i < constructor_count;
1498
jobject obj = is_constructor
1499
? env->GetObjectArrayElement(constructors, i)
1500
: env->GetObjectArrayElement(methods, i - constructor_count);
1501
ERR_CONTINUE(!obj);
1502
1503
String str_method;
1504
if (is_constructor) {
1505
str_method = "<init>";
1506
} else {
1507
jstring name = (jstring)env->CallObjectMethod(obj, Method_getName);
1508
str_method = jstring_to_string(name, env);
1509
env->DeleteLocalRef(name);
1510
}
1511
1512
Vector<String> params;
1513
1514
jint mods = env->CallIntMethod(obj, is_constructor ? Constructor_getModifiers : Method_getModifiers);
1515
bool is_public = (mods & 0x0001) != 0; // java.lang.reflect.Modifier.PUBLIC
1516
1517
if (!is_public && (is_constructor || !p_allow_non_public_methods_access)) {
1518
env->DeleteLocalRef(obj);
1519
continue; //not public bye
1520
}
1521
1522
jobjectArray param_types = (jobjectArray)env->CallObjectMethod(obj, is_constructor ? Constructor_getParameterTypes : Method_getParameterTypes);
1523
int count = env->GetArrayLength(param_types);
1524
1525
if (!java_class->methods.has(str_method)) {
1526
java_class->methods[str_method] = List<JavaClass::MethodInfo>();
1527
}
1528
1529
JavaClass::MethodInfo mi;
1530
mi._static = (mods & 0x8) != 0;
1531
mi._constructor = is_constructor;
1532
bool valid = true;
1533
String signature = "(";
1534
1535
for (int j = 0; j < count; j++) {
1536
jobject obj2 = env->GetObjectArrayElement(param_types, j);
1537
String strsig;
1538
uint32_t sig = 0;
1539
if (!_get_type_sig(env, obj2, sig, strsig)) {
1540
valid = false;
1541
env->DeleteLocalRef(obj2);
1542
break;
1543
}
1544
signature += strsig;
1545
mi.param_types.push_back(sig);
1546
mi.param_sigs.push_back(strsig);
1547
env->DeleteLocalRef(obj2);
1548
}
1549
1550
if (!valid) {
1551
print_line("Method can't be bound (unsupported arguments): " + class_name_dots + "::" + str_method);
1552
env->DeleteLocalRef(obj);
1553
env->DeleteLocalRef(param_types);
1554
continue;
1555
}
1556
1557
signature += ")";
1558
1559
if (is_constructor) {
1560
signature += "V";
1561
mi.return_type = JavaClass::ARG_TYPE_CLASS;
1562
} else {
1563
jobject return_type = (jobject)env->CallObjectMethod(obj, Method_getReturnType);
1564
1565
String strsig;
1566
uint32_t sig = 0;
1567
if (!_get_type_sig(env, return_type, sig, strsig)) {
1568
print_line("Method can't be bound (unsupported return type): " + class_name_dots + "::" + str_method);
1569
env->DeleteLocalRef(obj);
1570
env->DeleteLocalRef(param_types);
1571
env->DeleteLocalRef(return_type);
1572
continue;
1573
}
1574
1575
signature += strsig;
1576
mi.return_type = sig;
1577
1578
env->DeleteLocalRef(return_type);
1579
}
1580
1581
bool discard = false;
1582
1583
for (List<JavaClass::MethodInfo>::Element *E = java_class->methods[str_method].front(); E; E = E->next()) {
1584
float new_likeliness = 0;
1585
float existing_likeliness = 0;
1586
1587
if (E->get().param_types.size() != mi.param_types.size()) {
1588
continue;
1589
}
1590
bool this_valid = true;
1591
for (int j = 0; j < E->get().param_types.size(); j++) {
1592
Variant::Type _new;
1593
float new_l;
1594
Variant::Type existing;
1595
float existing_l;
1596
JavaClass::_convert_to_variant_type(E->get().param_types[j], existing, existing_l);
1597
JavaClass::_convert_to_variant_type(mi.param_types[j], _new, new_l);
1598
if (_new != existing) {
1599
this_valid = false;
1600
break;
1601
} else if ((_new == Variant::OBJECT || _new == Variant::ARRAY) && E->get().param_sigs[j] != mi.param_sigs[j]) {
1602
this_valid = false;
1603
break;
1604
}
1605
new_likeliness += new_l;
1606
existing_likeliness += existing_l;
1607
}
1608
1609
if (!this_valid) {
1610
continue;
1611
}
1612
1613
if (new_likeliness > existing_likeliness) {
1614
java_class->methods[str_method].erase(E);
1615
break;
1616
} else {
1617
discard = true;
1618
}
1619
}
1620
1621
if (!discard) {
1622
if (mi._static) {
1623
mi.method = env->GetStaticMethodID(bclass, str_method.utf8().get_data(), signature.utf8().get_data());
1624
} else {
1625
mi.method = env->GetMethodID(bclass, str_method.utf8().get_data(), signature.utf8().get_data());
1626
}
1627
1628
if (env->ExceptionCheck()) {
1629
// Exceptions may be thrown when trying to access hidden methods; write the exception to the logs and continue.
1630
env->ExceptionDescribe();
1631
env->ExceptionClear();
1632
continue;
1633
}
1634
1635
if (mi.method) {
1636
java_class->methods[str_method].push_back(mi);
1637
}
1638
}
1639
1640
env->DeleteLocalRef(obj);
1641
env->DeleteLocalRef(param_types);
1642
}
1643
1644
env->DeleteLocalRef(constructors);
1645
env->DeleteLocalRef(methods);
1646
1647
jobjectArray fields = (jobjectArray)env->CallObjectMethod(bclass, Class_getFields);
1648
1649
int count = env->GetArrayLength(fields);
1650
1651
for (int i = 0; i < count; i++) {
1652
jobject obj = env->GetObjectArrayElement(fields, i);
1653
ERR_CONTINUE(!obj);
1654
1655
jstring name = (jstring)env->CallObjectMethod(obj, Field_getName);
1656
String str_field = jstring_to_string(name, env);
1657
env->DeleteLocalRef(name);
1658
int mods = env->CallIntMethod(obj, Field_getModifiers);
1659
if ((mods & 0x8) && (mods & 0x10) && (mods & 0x1)) { //static final public!
1660
1661
jobject objc = env->CallObjectMethod(obj, Field_get, nullptr);
1662
if (objc) {
1663
uint32_t sig;
1664
String strsig;
1665
jclass cl = env->GetObjectClass(objc);
1666
if (JavaClassWrapper::_get_type_sig(env, cl, sig, strsig)) {
1667
if ((sig & JavaClass::ARG_TYPE_MASK) <= JavaClass::ARG_TYPE_STRING) {
1668
Variant value;
1669
if (JavaClass::_convert_object_to_variant(env, objc, value, sig)) {
1670
java_class->constant_map[str_field] = value;
1671
}
1672
}
1673
}
1674
1675
env->DeleteLocalRef(cl);
1676
}
1677
1678
env->DeleteLocalRef(objc);
1679
}
1680
env->DeleteLocalRef(obj);
1681
}
1682
1683
env->DeleteLocalRef(fields);
1684
env->DeleteLocalRef(bclass);
1685
1686
return java_class;
1687
}
1688
1689
Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_private_methods_access) {
1690
JNIEnv *env = get_jni_env();
1691
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
1692
1693
jstring class_name = (jstring)env->CallObjectMethod(p_class, Class_getName);
1694
String class_name_string = jstring_to_string(class_name, env);
1695
env->DeleteLocalRef(class_name);
1696
1697
return _wrap(class_name_string, p_allow_private_methods_access);
1698
}
1699
1700
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
1701
1702
JavaClassWrapper::JavaClassWrapper() {
1703
singleton = this;
1704
1705
JNIEnv *env = get_jni_env();
1706
ERR_FAIL_NULL(env);
1707
1708
jclass bclass = jni_find_class(env, "java/lang/Class");
1709
Class_getConstructors = env->GetMethodID(bclass, "getConstructors", "()[Ljava/lang/reflect/Constructor;");
1710
Class_getDeclaredMethods = env->GetMethodID(bclass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
1711
Class_getFields = env->GetMethodID(bclass, "getFields", "()[Ljava/lang/reflect/Field;");
1712
Class_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
1713
Class_getSuperclass = env->GetMethodID(bclass, "getSuperclass", "()Ljava/lang/Class;");
1714
env->DeleteLocalRef(bclass);
1715
1716
bclass = jni_find_class(env, "java/lang/reflect/Constructor");
1717
Constructor_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
1718
Constructor_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
1719
env->DeleteLocalRef(bclass);
1720
1721
bclass = jni_find_class(env, "java/lang/reflect/Method");
1722
Method_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
1723
Method_getReturnType = env->GetMethodID(bclass, "getReturnType", "()Ljava/lang/Class;");
1724
Method_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
1725
Method_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
1726
env->DeleteLocalRef(bclass);
1727
1728
bclass = jni_find_class(env, "java/lang/reflect/Field");
1729
Field_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
1730
Field_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
1731
Field_get = env->GetMethodID(bclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
1732
env->DeleteLocalRef(bclass);
1733
1734
bclass = jni_find_class(env, "java/lang/Boolean");
1735
Boolean_booleanValue = env->GetMethodID(bclass, "booleanValue", "()Z");
1736
env->DeleteLocalRef(bclass);
1737
1738
bclass = jni_find_class(env, "java/lang/Byte");
1739
Byte_byteValue = env->GetMethodID(bclass, "byteValue", "()B");
1740
env->DeleteLocalRef(bclass);
1741
1742
bclass = jni_find_class(env, "java/lang/Character");
1743
Character_characterValue = env->GetMethodID(bclass, "charValue", "()C");
1744
env->DeleteLocalRef(bclass);
1745
1746
bclass = jni_find_class(env, "java/lang/Short");
1747
Short_shortValue = env->GetMethodID(bclass, "shortValue", "()S");
1748
env->DeleteLocalRef(bclass);
1749
1750
bclass = jni_find_class(env, "java/lang/Integer");
1751
Integer_integerValue = env->GetMethodID(bclass, "intValue", "()I");
1752
env->DeleteLocalRef(bclass);
1753
1754
bclass = jni_find_class(env, "java/lang/Long");
1755
Long_longValue = env->GetMethodID(bclass, "longValue", "()J");
1756
env->DeleteLocalRef(bclass);
1757
1758
bclass = jni_find_class(env, "java/lang/Float");
1759
Float_floatValue = env->GetMethodID(bclass, "floatValue", "()F");
1760
env->DeleteLocalRef(bclass);
1761
1762
bclass = jni_find_class(env, "java/lang/Double");
1763
Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D");
1764
env->DeleteLocalRef(bclass);
1765
}
1766
1767