https://github.com/wang-bin/jmi
JNI Modern Interface in C++17
https://github.com/wang-bin/jmi
android java jmi jni modern-cpp ndk
Last synced: 9 months ago
JSON representation
JNI Modern Interface in C++17
- Host: GitHub
- URL: https://github.com/wang-bin/jmi
- Owner: wang-bin
- License: mit
- Created: 2016-11-28T15:25:23.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2025-01-01T06:56:46.000Z (about 1 year ago)
- Last Synced: 2025-03-31T08:12:09.422Z (10 months ago)
- Topics: android, java, jmi, jni, modern-cpp, ndk
- Language: C++
- Homepage:
- Size: 167 KB
- Stars: 79
- Watchers: 8
- Forks: 17
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# JMI
**_JNI Modern Interface in C++_**
[中文](README_zh_CN.md)
[Some Java Classes Written in JMI](https://github.com/wang-bin/AND.git)
[](https://github.com/wang-bin/JMI/actions)
### Features
- Compile time computed signature constant(C++17)
- Support both In & Out parameters for Java methods
- Per class jclass cache, per method jmethodID cache, per field jfieldID cache
- The same C++/Java storage duration: a static java member maps to a static member in C++
- Get rid of local reference leak
- getEnv() at any thread without caring about when to detach
- Signature is generated by compiler only once
- Supports JNI primitive types(jint, jlong etc. but not int, long), JMI's JObject, C/C++ string and array of these types as method parameter type, return type and field type.
- Provide frequently used functions for convenience: `to_string(jstring, JNIEnv*)`, `from_string(std::string, JNIEnv*)`, `android::application()`
- Easy to use. Minimize user code
- Exception handling in every call
### Example:
- Setup java vm in `JNI_OnLoad`: `jmi::javaVM(vm);`
- Create a SurfaceTexture:
```
// define SurfaceTexture tag class in any scope visibile by jmi::JObject
struct SurfaceTexture : jmi::ClassTag { static constexpr auto name() {return JMISTR("android/graphics/SurfaceTexture");}}; // or JMISTR("android.graphics.SurfaceTexture")
...
GLuint tex = ...
...
jmi::JObject texture;
if (!texture.create(tex)) {
// texture.error() ...
}
```
- Create Surface from SurfaceTexture:
```
struct Surface : jmi::ClassTag { static constexpr auto name() {return JMISTR("android.view.Surface");}}; // '.' or '/'
...
jmi::JObject surface;
surface.create(texture);
```
- Call void method:
```
texture.call("updateTexImage");
```
or
```
texture.call("updateTexImage");
```
- Call method with output parameters:
```
float mat4[16]; // or std::array, valarray
texture.call("getTransformMatrix", std::ref(mat4)); // use std::ref() if parameter should be modified by jni method
```
If out parameter is of type `JObject<...>` or it's subclass, `std::ref()` is not required because the object does not change, only some fields may be changed. For example:
```
MediaCodec::BufferInfo bi;
bi.create();
codec.dequeueOutputBuffer(bi, timeout); // bi is of type MediaCodec::BufferInfo&
```
- Call method with a return type:
```
auto t = texture.call("getTimestamp");
```
## jmethodID Cache
`GetMethodID/GetStaticMethodID()` is always called in `call/callStatic("methodName", ....)` every time, while it's called only once in overload one `call/callStatic<...MTag>(...)`, where `MTag` is a subclass of `jmi:MethodTag` implementing `static const char* name() { return "methodName";}`.
```
// GetMethodID() will be invoked only once for each method in the scope of MethodTag subclass
struct UpdateTexImage : jmi::MethodTag { static const char* name() {return "updateTexImage";}};
struct GetTimestamp : jmi::MethodTag { static const char* name() {return "getTimestamp";}};
struct GetTransformMatrix : jmi::MethodTag { static const char* name() {return "getTransformMatrix";}};
...
texture.call(); // or texture.call();
auto t = texture.call();
texture.call(std::ref(mat4)); // use std::ref() if parameter should be modified by jni method
```
### Field API
Field api supports cacheable and uncacheable jfieldID. Field object can be JNI basic types, string, JObject and array of these types.
Cacheable jfieldID through FieldTag
```
JObject obj;
...
struct MyIntField : FieldTag { static const char* name() {return "myIntFieldName";} };
auto ifield = obj.field();
jfieldID ifid = ifield; // or ifield.id()
ifield.set(1234);
jint ivalue = ifield; // or ifield.get();
// static field is the same except using the static function JObject::staticField
struct MyStrFieldS : FieldTag { static const char* name() {return "myStaticStrFieldName";} };
auto& ifields = JObject::staticField(); // it can be an ref
jfieldID ifids = ifields; // or ifield.id()
ifields.set("JMI static field test");
ifields = "assign";
std::string ivalues = ifields; // or ifield.get();
```
Uncacheable jfieldID using field name string directly
```
auto ifield = obj.field("myIntFieldName");
...
```
### Writting a C++ Class for a Java Class
Create a class inherits JObject or stores it as a member, or use CRTP JObject. Each method implementation is usually less then 2 lines of code. See [JMITest](test/JMITest.h) and [Project AND](https://github.com/wang-bin/AND.git)
### Using Signatures Generated by Compiler
The function template `auto signature_of()` returns the signature of type T. T can be JMI supported types (except jobject types because the class is determined at runtime), reference_wrapper, void, and function types whose return type and parameter types are of above types.
example:
```
void native_test_impl(JNIEnv *env , jobject thiz, ...) {}
staitc const JNINativeMethod gMethods[] = {
{"native_test", signature_of(native_test_impl).data(), native_test_impl},
...
};
```
You may find that a macro can simplify above example:
```
#define DEFINE_METHOD(M) {#M, signature_of(M##_impl).data(), M##_impl}
staitc const JNINativeMethod gMethods[] = {
DEFINE_METHOD(native_test),
...
}
```
### Known Issues
- If return type and first n arguments of call/call_static are the same, explicitly specifying return type and n arguments type is required
### Why JObject is a Template?
- To support per class jclass, per method jmethodID, per field jfieldID cache
#### Compilers
c++14/17 is required
- g++ >= 4.9.0(except 8.0~8.3)
- clang >= 3.5
- msvc>= 19.0
- icc >= 17.0
### TODO
- modern C++ class generator script
#### MIT License
>Copyright (c) 2016-2021 WangBin