{"id":19602555,"url":"https://github.com/wang-bin/jmi","last_synced_at":"2025-04-07T10:25:30.006Z","repository":{"id":141348749,"uuid":"74986195","full_name":"wang-bin/JMI","owner":"wang-bin","description":"JNI Modern Interface in C++17","archived":false,"fork":false,"pushed_at":"2025-01-01T06:56:46.000Z","size":171,"stargazers_count":79,"open_issues_count":0,"forks_count":17,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-31T08:12:09.422Z","etag":null,"topics":["android","java","jmi","jni","modern-cpp","ndk"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wang-bin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-28T15:25:23.000Z","updated_at":"2025-01-07T14:50:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"5346cd7d-991d-485c-9480-36892de6ccce","html_url":"https://github.com/wang-bin/JMI","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-bin%2FJMI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-bin%2FJMI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-bin%2FJMI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-bin%2FJMI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wang-bin","download_url":"https://codeload.github.com/wang-bin/JMI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247633735,"owners_count":20970385,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","java","jmi","jni","modern-cpp","ndk"],"created_at":"2024-11-11T09:24:51.066Z","updated_at":"2025-04-07T10:25:29.988Z","avatar_url":"https://github.com/wang-bin.png","language":"C++","readme":"# JMI\n**_JNI Modern Interface in C++_**\n\n[中文](README_zh_CN.md)\n\n[Some Java Classes Written in JMI](https://github.com/wang-bin/AND.git)\n\n[![Build status github](https://github.com/wang-bin/JMI/workflows/Build/badge.svg)](https://github.com/wang-bin/JMI/actions)\n\n### Features\n\n- Compile time computed signature constant(C++17)\n- Support both In \u0026 Out parameters for Java methods\n- Per class jclass cache, per method jmethodID cache, per field jfieldID cache\n- The same C++/Java storage duration: a static java member maps to a static member in C++\n- Get rid of local reference leak\n- getEnv() at any thread without caring about when to detach\n- Signature is generated by compiler only once\n- 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.\n- Provide frequently used functions for convenience: `to_string(jstring, JNIEnv*)`, `from_string(std::string, JNIEnv*)`, `android::application()`\n- Easy to use. Minimize user code\n- Exception handling in every call\n\n### Example:\n- Setup java vm in `JNI_OnLoad`: `jmi::javaVM(vm);`\n\n- Create a SurfaceTexture:\n```\n    // define SurfaceTexture tag class in any scope visibile by jmi::JObject\u003cSurfaceTexture\u003e\n    struct SurfaceTexture : jmi::ClassTag { static constexpr auto name() {return JMISTR(\"android/graphics/SurfaceTexture\");}}; // or JMISTR(\"android.graphics.SurfaceTexture\")\n    ...\n    GLuint tex = ...\n    ...\n    jmi::JObject\u003cSurfaceTexture\u003e texture;\n    if (!texture.create(tex)) {\n        // texture.error() ...\n    }\n```\n\n- Create Surface from SurfaceTexture:\n```\n    struct Surface : jmi::ClassTag { static constexpr auto name() {return JMISTR(\"android.view.Surface\");}}; // '.' or '/'\n    ...\n    jmi::JObject\u003cSurface\u003e surface;\n    surface.create(texture);\n```\n\n- Call void method:\n```\n    texture.call(\"updateTexImage\");\n```\n\nor\n\n```\n    texture.call\u003cvoid\u003e(\"updateTexImage\");\n```\n\n- Call method with output parameters:\n```\n    float mat4[16]; // or std::array\u003cfloat, 16\u003e, valarray\u003cfloat\u003e\n    texture.call(\"getTransformMatrix\", std::ref(mat4)); // use std::ref() if parameter should be modified by jni method\n```\n\nIf out parameter is of type `JObject\u003c...\u003e` or it's subclass, `std::ref()` is not required because the object does not change, only some fields may be changed. For example:\n\n```\n    MediaCodec::BufferInfo bi;\n    bi.create();\n    codec.dequeueOutputBuffer(bi, timeout);  // bi is of type MediaCodec::BufferInfo\u0026\n```\n\n- Call method with a return type:\n```\n    auto t = texture.call\u003cjlong\u003e(\"getTimestamp\");\n```\n\n## jmethodID Cache\n\n `GetMethodID/GetStaticMethodID()` is always called in `call/callStatic(\"methodName\", ....)` every time, while it's called only once in overload one `call/callStatic\u003c...MTag\u003e(...)`, where `MTag` is a subclass of `jmi:MethodTag` implementing `static const char* name() { return \"methodName\";}`.\n\n```\n    // GetMethodID() will be invoked only once for each method in the scope of MethodTag subclass\n    struct UpdateTexImage : jmi::MethodTag { static const char* name() {return \"updateTexImage\";}};\n    struct GetTimestamp : jmi::MethodTag { static const char* name() {return \"getTimestamp\";}};\n    struct GetTransformMatrix : jmi::MethodTag { static const char* name() {return \"getTransformMatrix\";}};\n    ...\n    texture.call\u003cUpdateTexImage\u003e(); // or texture.call\u003cvoid,UpdateTexImage\u003e();\n    auto t = texture.call\u003cjlong, GetTimestamp\u003e();\n    texture.call\u003cGetTransformMatrix\u003e(std::ref(mat4)); // use std::ref() if parameter should be modified by jni method\n```\n\n### Field API\n\nField api supports cacheable and uncacheable jfieldID. Field object can be JNI basic types, string, JObject and array of these types.\n\nCacheable jfieldID through FieldTag\n\n```\n    JObject\u003cMyClassTag\u003e obj;\n    ...\n    struct MyIntField : FieldTag { static const char* name() {return \"myIntFieldName\";} };\n    auto ifield = obj.field\u003cjint, MyIntField\u003e();\n    jfieldID ifid = ifield; // or ifield.id()\n    ifield.set(1234);\n    jint ivalue = ifield; // or ifield.get();\n\n    // static field is the same except using the static function JObject::staticField\n    struct MyStrFieldS : FieldTag { static const char* name() {return \"myStaticStrFieldName\";} };\n    auto\u0026 ifields = JObject\u003cMyClassTag\u003e::staticField\u003cstd::string, MyIntFieldS\u003e(); // it can be an ref\n    jfieldID ifids = ifields; // or ifield.id()\n    ifields.set(\"JMI static field test\");\n    ifields = \"assign\";\n    std::string ivalues = ifields; // or ifield.get();\n```\n\nUncacheable jfieldID using field name string directly\n\n```\n    auto ifield = obj.field\u003cjint\u003e(\"myIntFieldName\");\n    ...\n```\n\n### Writting a C++ Class for a Java Class\n\nCreate a class inherits JObject\u003cYouClassTag\u003e or stores it as a member, or use CRTP JObject\u003cYouClass\u003e. 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)\n\n### Using Signatures Generated by Compiler\n\nThe function template `auto signature_of\u003cT\u003e()` 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.\n\nexample:\n\n```\n    void native_test_impl(JNIEnv *env , jobject thiz, ...) {}\n\n    staitc const JNINativeMethod gMethods[] = {\n        {\"native_test\", signature_of(native_test_impl).data(), native_test_impl},\n        ...\n    };\n```\n\nYou may find that a macro can simplify above example:\n\n```\n    #define DEFINE_METHOD(M) {#M, signature_of(M##_impl).data(), M##_impl}\n    staitc const JNINativeMethod gMethods[] = {\n        DEFINE_METHOD(native_test),\n        ...\n    }\n```\n\n\n### Known Issues\n\n- If return type and first n arguments of call/call_static are the same, explicitly specifying return type and n arguments type is required\n\n### Why JObject is a Template?\n- To support per class jclass, per method jmethodID, per field jfieldID cache\n\n#### Compilers\n\nc++14/17 is required\n\n- g++ \u003e= 4.9.0(except 8.0~8.3)\n- clang \u003e= 3.5\n- msvc\u003e= 19.0\n- icc \u003e= 17.0\n\n\n### TODO\n- modern C++ class generator script\n\n#### MIT License\n\u003eCopyright (c) 2016-2021 WangBin\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwang-bin%2Fjmi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwang-bin%2Fjmi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwang-bin%2Fjmi/lists"}