6
6
#else
7
7
// UNIX Dependencies
8
8
# include < dlfcn.h>
9
+ # include < unistd.h>
10
+ # include < tuple>
9
11
#endif
10
12
11
13
// External Dependencies
@@ -24,6 +26,14 @@ namespace jni
24
26
static std::atomic_bool isVm (false );
25
27
static JavaVM* javaVm = nullptr ;
26
28
29
+ static bool getEnv (JavaVM *vm, JNIEnv **env) {
30
+ return vm->GetEnv ((void **)env, JNI_VERSION_1_2) == JNI_OK;
31
+ }
32
+
33
+ static bool isAttached (JavaVM *vm) {
34
+ JNIEnv *env = nullptr ;
35
+ return getEnv (vm, &env);
36
+ }
27
37
/* *
28
38
Maintains the lifecycle of a JNIEnv.
29
39
*/
@@ -57,7 +67,7 @@ namespace jni
57
67
if (vm == nullptr )
58
68
throw InitializationException (" JNI not initialized" );
59
69
60
- if (vm-> GetEnv (( void **)&_env, JNI_VERSION_1_2) != JNI_OK )
70
+ if (! getEnv (vm, &_env) )
61
71
{
62
72
#ifdef __ANDROID__
63
73
if (vm->AttachCurrentThread (&_env, nullptr ) != 0 )
@@ -150,8 +160,17 @@ namespace jni
150
160
{
151
161
static thread_local ScopedEnv env;
152
162
163
+ if (env.get () != nullptr && !isAttached (javaVm))
164
+ {
165
+ // we got detached, so clear it.
166
+ // will be re-populated from static javaVm below.
167
+ env = ScopedEnv{};
168
+ }
169
+
153
170
if (env.get () == nullptr )
171
+ {
154
172
env.init (javaVm);
173
+ }
155
174
156
175
return env.get ();
157
176
}
@@ -353,20 +372,20 @@ namespace jni
353
372
return _handle == nullptr || env ()->IsSameObject (_handle, nullptr );
354
373
}
355
374
356
- template <> void Object::callMethod (method_t method, internal::value_t * args) const
375
+ void Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< void > const & ) const
357
376
{
358
377
env ()->CallVoidMethodA (_handle, method, (jvalue*) args);
359
378
handleJavaExceptions ();
360
379
}
361
380
362
- template <> bool Object::callMethod (method_t method, internal::value_t * args) const
381
+ bool Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< bool > const & ) const
363
382
{
364
383
auto result = env ()->CallBooleanMethodA (_handle, method, (jvalue*) args);
365
384
handleJavaExceptions ();
366
385
return result != 0 ;
367
386
}
368
387
369
- template <> bool Object::get (field_t field) const
388
+ bool Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< bool > const & ) const
370
389
{
371
390
return env ()->GetBooleanField (_handle, field) != 0 ;
372
391
}
@@ -376,122 +395,122 @@ namespace jni
376
395
env ()->SetBooleanField (_handle, field, value);
377
396
}
378
397
379
- template <> byte_t Object::callMethod (method_t method, internal::value_t * args) const
398
+ byte_t Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< byte_t > const & ) const
380
399
{
381
400
auto result = env ()->CallByteMethodA (_handle, method, (jvalue*) args);
382
401
handleJavaExceptions ();
383
402
return result;
384
403
}
385
404
386
- template <> wchar_t Object::callMethod (method_t method, internal::value_t * args) const
405
+ wchar_t Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< wchar_t > const & ) const
387
406
{
388
407
auto result = env ()->CallCharMethodA (_handle, method, (jvalue*) args);
389
408
handleJavaExceptions ();
390
409
return result;
391
410
}
392
411
393
- template <> short Object::callMethod (method_t method, internal::value_t * args) const
412
+ short Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< short > const & ) const
394
413
{
395
414
auto result = env ()->CallShortMethodA (_handle, method, (jvalue*) args);
396
415
handleJavaExceptions ();
397
416
return result;
398
417
}
399
418
400
- template <> int Object::callMethod (method_t method, internal::value_t * args) const
419
+ int Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< int > const & ) const
401
420
{
402
421
auto result = env ()->CallIntMethodA (_handle, method, (jvalue*) args);
403
422
handleJavaExceptions ();
404
423
return result;
405
424
}
406
425
407
- template <> long long Object::callMethod (method_t method, internal::value_t * args) const
426
+ long long Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< long long > const & ) const
408
427
{
409
428
auto result = env ()->CallLongMethodA (_handle, method, (jvalue*) args);
410
429
handleJavaExceptions ();
411
430
return result;
412
431
}
413
432
414
- template <> float Object::callMethod (method_t method, internal::value_t * args) const
433
+ float Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< float > const & ) const
415
434
{
416
435
auto result = env ()->CallFloatMethodA (_handle, method, (jvalue*) args);
417
436
handleJavaExceptions ();
418
437
return result;
419
438
}
420
439
421
- template <> double Object::callMethod (method_t method, internal::value_t * args) const
440
+ double Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper< double > const & ) const
422
441
{
423
442
auto result = env ()->CallDoubleMethodA (_handle, method, (jvalue*) args);
424
443
handleJavaExceptions ();
425
444
return result;
426
445
}
427
446
428
- template <> std::string Object::callMethod (method_t method, internal::value_t * args) const
447
+ std::string Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper<std::string> const & ) const
429
448
{
430
449
auto result = env ()->CallObjectMethodA (_handle, method, (jvalue*) args);
431
450
handleJavaExceptions ();
432
451
return toString (result);
433
452
}
434
453
435
- template <> std::wstring Object::callMethod (method_t method, internal::value_t * args) const
454
+ std::wstring Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper<std::wstring> const & ) const
436
455
{
437
456
auto result = env ()->CallObjectMethodA (_handle, method, (jvalue*) args);
438
457
handleJavaExceptions ();
439
458
return toWString (result);
440
459
}
441
460
442
- template <> jni::Object Object::callMethod (method_t method, internal::value_t * args) const
461
+ jni::Object Object::callMethod (method_t method, internal::value_t * args, internal::ReturnTypeWrapper<jni::Object> const & ) const
443
462
{
444
463
auto result = env ()->CallObjectMethodA (_handle, method, (jvalue*) args);
445
464
handleJavaExceptions ();
446
465
return Object (result, DeleteLocalInput);
447
466
}
448
467
449
- template <> byte_t Object::get (field_t field) const
468
+ byte_t Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< byte_t > const & ) const
450
469
{
451
470
return env ()->GetByteField (_handle, field);
452
471
}
453
472
454
- template <> wchar_t Object::get (field_t field) const
473
+ wchar_t Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< wchar_t > const & ) const
455
474
{
456
475
return env ()->GetCharField (_handle, field);
457
476
}
458
477
459
- template <> short Object::get (field_t field) const
478
+ short Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< short > const & ) const
460
479
{
461
480
return env ()->GetShortField (_handle, field);
462
481
}
463
482
464
- template <> int Object::get (field_t field) const
483
+ int Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< int > const & ) const
465
484
{
466
485
return env ()->GetIntField (_handle, field);
467
486
}
468
487
469
- template <> long long Object::get (field_t field) const
488
+ long long Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< long long > const & ) const
470
489
{
471
490
return env ()->GetLongField (_handle, field);
472
491
}
473
492
474
- template <> float Object::get (field_t field) const
493
+ float Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< float > const & ) const
475
494
{
476
495
return env ()->GetFloatField (_handle, field);
477
496
}
478
497
479
- template <> double Object::get (field_t field) const
498
+ double Object::getFieldValue (field_t field, internal::ReturnTypeWrapper< double > const & ) const
480
499
{
481
500
return env ()->GetDoubleField (_handle, field);
482
501
}
483
502
484
- template <> std::string Object::get (field_t field) const
503
+ std::string Object::getFieldValue (field_t field, internal::ReturnTypeWrapper<std::string> const & ) const
485
504
{
486
505
return toString (env ()->GetObjectField (_handle, field));
487
506
}
488
507
489
- template <> std::wstring Object::get (field_t field) const
508
+ std::wstring Object::getFieldValue (field_t field, internal::ReturnTypeWrapper<std::wstring> const & ) const
490
509
{
491
510
return toWString (env ()->GetObjectField (_handle, field));
492
511
}
493
512
494
- template <> Object Object::get (field_t field) const
513
+ Object Object::getFieldValue (field_t field, internal::ReturnTypeWrapper<Object> const & ) const
495
514
{
496
515
return Object (env ()->GetObjectField (_handle, field), DeleteLocalInput);
497
516
}
@@ -1270,7 +1289,57 @@ namespace jni
1270
1289
1271
1290
typedef jint (JNICALL *CreateVm_t)(JavaVM**, void **, void *);
1272
1291
1292
+ #ifndef _WIN32
1293
+ static bool fileExists (const std::string& filePath)
1294
+ {
1295
+ return access (filePath.c_str (), F_OK) != -1 ;
1296
+ }
1273
1297
1298
+ template <size_t N>
1299
+ static ssize_t readlink_safe (const char *pathname, char (&output)[N]) {
1300
+ auto len = readlink (pathname, output, N - 1 );
1301
+ if (len > 0 ) {
1302
+ output[len] = ' \0 ' ;
1303
+ }
1304
+ return len;
1305
+ }
1306
+
1307
+ static std::pair<ssize_t , std::string>
1308
+ readlink_as_string (const char *pathname) {
1309
+ char buf[2048 ] = {};
1310
+ auto len = readlink_safe (pathname, buf);
1311
+ if (len <= 0 ) {
1312
+ return {len, {}};
1313
+ }
1314
+ return {len, std::string{buf, static_cast <size_t >(len)}};
1315
+ }
1316
+ static std::string readlink_deep (const char *pathname) {
1317
+ std::string prev{pathname};
1318
+ ssize_t len = 0 ;
1319
+ std::string next;
1320
+ while (true ) {
1321
+ std::tie (len, next) = readlink_as_string (prev.c_str ());
1322
+ if (!next.empty ()) {
1323
+ prev = next;
1324
+ } else {
1325
+ return prev;
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ static std::string drop_path_components (const std::string & path, size_t num_components) {
1331
+ size_t pos = std::string::npos;
1332
+ size_t slash_pos = std::string::npos;
1333
+ for (size_t i = 0 ; i < num_components; ++i) {
1334
+ slash_pos = path.find_last_of (' /' , pos);
1335
+ if (slash_pos == std::string::npos || slash_pos == 0 ) {
1336
+ return {};
1337
+ }
1338
+ pos = slash_pos - 1 ;
1339
+ }
1340
+ return std::string{path.c_str (), slash_pos};
1341
+ }
1342
+ #endif
1274
1343
static std::string detectJvmPath ()
1275
1344
{
1276
1345
std::string result;
@@ -1321,7 +1390,7 @@ namespace jni
1321
1390
javaHome + " \\ bin\\ server\\ jvm.dll"
1322
1391
};
1323
1392
1324
- for (auto i : options)
1393
+ for (auto const & i : options)
1325
1394
if (fileExists (i))
1326
1395
return i;
1327
1396
}
@@ -1338,6 +1407,28 @@ namespace jni
1338
1407
#endif
1339
1408
result = libJvmPath;
1340
1409
} else {
1410
+ std::string path = readlink_deep (" /usr/bin/java" );
1411
+ if (!path.empty ()) {
1412
+ // drop bin and java
1413
+ auto javaHome = drop_path_components (path, 2 );
1414
+ if (!javaHome.empty ()) {
1415
+ std::string options[] = {
1416
+ javaHome + " /jre/lib/amd64/server/libjvm.so" ,
1417
+ javaHome + " /jre/lib/amd64/client/libjvm.so" ,
1418
+ javaHome + " /jre/lib/server/libjvm.so" ,
1419
+ javaHome + " /jre/lib/client/libjvm.so" ,
1420
+ javaHome + " /lib/server/libjvm.so" ,
1421
+ javaHome + " /lib/client/libjvm.so" ,
1422
+ };
1423
+
1424
+ for (auto const &i : options) {
1425
+ fprintf (stderr, " trying %s\n " , i.c_str ());
1426
+ if (fileExists (i)) {
1427
+ return i;
1428
+ }
1429
+ }
1430
+ }
1431
+ }
1341
1432
// Best guess so far.
1342
1433
result = " /usr/lib/jvm/default-java/jre/lib/amd64/server/libjvm.so" ;
1343
1434
}
0 commit comments