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