{"id":16405699,"url":"https://github.com/aecsocket/jni-glue","last_synced_at":"2025-02-23T19:24:12.214Z","repository":{"id":129001418,"uuid":"598835905","full_name":"aecsocket/jni-glue","owner":"aecsocket","description":"Lightweight library for generating native JNI code from annotations","archived":false,"fork":false,"pushed_at":"2023-02-23T22:30:47.000Z","size":153,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-05T11:43:03.545Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","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/aecsocket.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2023-02-07T22:38:01.000Z","updated_at":"2023-02-07T22:38:19.000Z","dependencies_parsed_at":"2023-03-29T20:47:29.827Z","dependency_job_id":null,"html_url":"https://github.com/aecsocket/jni-glue","commit_stats":{"total_commits":10,"total_committers":1,"mean_commits":10.0,"dds":0.0,"last_synced_commit":"8520ec3ee022adfab151272d23f28a0afca2c94e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aecsocket%2Fjni-glue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aecsocket%2Fjni-glue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aecsocket%2Fjni-glue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aecsocket%2Fjni-glue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aecsocket","download_url":"https://codeload.github.com/aecsocket/jni-glue/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240366161,"owners_count":19790036,"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":[],"created_at":"2024-10-11T06:07:02.462Z","updated_at":"2025-02-23T19:24:12.153Z","avatar_url":"https://github.com/aecsocket.png","language":"Kotlin","readme":"\u003cdiv align=\"center\"\u003e\n\n# JniGlue\n[![License](https://img.shields.io/github/license/aecsocket/jni-glue)](LICENSE)\n[![CI](https://img.shields.io/github/actions/workflow/status/aecsocket/jni-glue/build.yml)](https://github.com/aecsocket/jni-glue/actions/workflows/build.yml)\n![Release](https://img.shields.io/maven-central/v/io.github.aecsocket/jni-glue-annotations?label=release)\n![Snapshot](https://img.shields.io/nexus/s/io.github.aecsocket/jni-glue-annotations?label=snapshot\u0026server=https%3A%2F%2Fs01.oss.sonatype.org)\n\nLightweight library for generating C++ JNI code for a Java project\n\n---\n\n\u003c/div\u003e\n\nThis allows you to use annotations to write C++ code directly in Java source code:\n\n```java\n@JniNative(\"foobar/FooBarJNI\")\npublic class FooBarLibrary {\n    public static int addTen(int value) {\n        return _addTen(value);\n    }\n    @JniBind(\"return value + 10;\")\n    public static native int _addTen(int value);\n    \n    public static void testNatives() {\n        int value = addTen(15);\n        System.out.println(\"Value is \" + value);\n        // \"Value is 25\"\n    }\n}\n```\n\n## Usage\n\n```kotlin\n// RECOMMENDED: if using Java, set the language version to at least 15\n// to use text block literals\njava {\n    toolchain.languageVersion.set(JavaLanguageVersion.of(15))\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation(\"io.github.aecsocket\", \"jni-glue-annotations\", \"VERSION\")\n    annotationProcessor(\"io.github.aecsocket\", \"jni-glue-processor\", \"VERSION\")\n}\n```\n\n### Loading the natives\n\nUse `JniPlatform.get()` to get which platform the host is currently running. You can use this to determine the file name\nof the native library to load:\n\n```\n# file structure\nfoobar/libfoobar-bindings.so\nfoobar/foobar-bindings.dll\nfoobar/libfoobar-bindings.dylib\n```\n\n```java\nJniPlatform platform = JniPlatform.get(); // e.g. WINDOWS, LINUX\nString fileName = platform.mapLibraryName(\"foobar-bindings\"); // e.g. libfoobar-bindings.so\nSystem.load(fileName);\n```\n\n### JNI models\n\nUse `@JniNative` to mark a file as part of a JNI model:\n\n```java\n@JniNative(FooBarLibrary.JNI_MODEL)\npublic final class FooBarLibrary {\n    public static final String JNI_MODEL = \"foobar/FooBarJNI\";\n}\n```\n\n**Note:** `@JniNative` is an inherited annotation, so you do *not* need to specify it on classes which extend a class\nannotated with it. A common pattern for this is:\n\n```java\n@JniNative(FooBarLibrary.JNI_MODEL)\npublic class FooBarNative {\n    protected long address;\n    \n    public FooBarNative(long address) {\n        this.address = address;\n    }\n}\n\n// no JniNative annotation required\npublic class BazObject extends FooBarNative {\n    public BazObject(long address) {\n        super(address);\n    }\n}\n```\n\nAfterwards you can use any of the `@Jni-` annotations:\n\n#### Java to C++\n\nAnnotate a method as `@JniBind` to bind a Java method to a native function - in Java 15, you can use multiline strings\nto include multiple lines:\n\n```java\n@JniNative(FooBarLibrary.JNI_MODEL)\npublic final class FooBarLibrary {\n    public static final String JNI_MODEL = \"foobar/FooBarJNI\";\n\n    public static void init() { _init(); }\n    @JniBind(\"\"\"\n            FooBar::preInit();\n            FooBar::init();\"\"\")\n    private static native void _init(); // note: the `_` prefix is automatically removed in generated natives \n}\n```\n\nA common situation is to wrap native objects in memory by creating a Java class which acts as a pointer, by storing\na `long address` which stores the object's address in memory. JniGlue has built-in support for this by annotating the\nclass with `@JniTypeMapping([native type])`, then using `@JniBindSelf` with `self` as a `[native type]*` (pointer):\n\n```cpp\nclass Baz {\n    public:\n        int mNumber;\n}\n```\n\n```java\n@JniNative(FooBarLibrary.JNI_MODEL)\n@JniTypeMapping(\"Baz\")\npublic final class Baz {\n    private long address;\n    \n    private Baz(long address) { this.address = address; }\n    public static Baz ref(long address) { return address == 0 ? null : new Baz(address); }\n    \n    public int getNumber() { return _getNumber(address); }\n    // `auto* self = (Baz*) _a;`\n    @JniBindSelf(\"return self-\u003emNumber;\")\n    private static native int _getNumber(long _a); // first argument must be `long _a`\n}\n```\n\n#### C++ to Java\n\nAnnotate a class as `@JniReferenced` to generate a `jclass jni_[class name]` field, which is automatically found\nand set to the corresponding Java class on load. You can then annotate (non-native) methods inside as `@JniCallback` to\ngenerate `jmethodID jni_[class name]_[method name]` fields and `JNI_[class name]_[method name](JNIEnv* env, ...)`\nfunctions to use in your code:\n\n```java\n@JniNative(FooBarLibrary.JNI_MODEL)\n@JniReferenced\npublic abstract class LibraryCallback {\n    public abstract void onError(ErrorCodeEnum errorCode);\n    @JniCallback\n    private void _onError(int errorCode) { onError(ErrorCodeEnum.values()[errorCode]); }\n}\n```\n\n```cpp\nclass LibraryCallbackImpl : LibraryCallback {\n    public:\n        JNIEnv* env;\n        jobject objectGlobalRef;\n        \n        LibraryCallbackImpl(JNIEnv* env, jobject obj) : env(env), objectGlobalRef(obj) {}\n    \n        void OnError(int errorCode) override {\n            JNI_LibraryCallback_onError(env, objectGlobalRef, errorCode);\n        }\n}\n\n// ...\n    FooBarLibrary::setCallback(new LibraryCallbackImpl(env, object));\n```\n\n### Using the generated JNI code\n\nA header file of the generated code will be output in the `build/generated/sources/annotationProcessor` directory. You can then\ninclude this header file in another C++ Gradle subproject to generate a library file from the code:\n\n```kotlin\nplugins {\n    id(\"cpp-library\")\n}\n\nlibrary {\n    binaries.configureEach {\n        val compileTask = compileTask.get()\n        compileTask.dependsOn(\":compileJava\") // to generate the header file first\n        compileTask.includes(\"${rootProject.buildDir}/generated/sources/annotationProcessor/java/main/foobar/\")\n    }\n}\n```\n\n```cpp\n#include \u003cFooBarJNI.h\u003e\n```\n\n## Building from source\n\n```sh\ngit clone https://github.com/aecsocket/jni-glue\ncd jni-glue\n./gradlew build\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faecsocket%2Fjni-glue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faecsocket%2Fjni-glue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faecsocket%2Fjni-glue/lists"}