Coder Social home page Coder Social logo

jni-glue's Introduction

JniGlue

License CI Release Snapshot

Lightweight library for generating C++ JNI code for a Java project


This allows you to use annotations to write C++ code directly in Java source code:

@JniNative("foobar/FooBarJNI")
public class FooBarLibrary {
    public static int addTen(int value) {
        return _addTen(value);
    }
    @JniBind("return value + 10;")
    public static native int _addTen(int value);
    
    public static void testNatives() {
        int value = addTen(15);
        System.out.println("Value is " + value);
        // "Value is 25"
    }
}

Usage

// RECOMMENDED: if using Java, set the language version to at least 15
// to use text block literals
java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(15))
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.aecsocket", "jni-glue-annotations", "VERSION")
    annotationProcessor("io.github.aecsocket", "jni-glue-processor", "VERSION")
}

Loading the natives

Use JniPlatform.get() to get which platform the host is currently running. You can use this to determine the file name of the native library to load:

# file structure
foobar/libfoobar-bindings.so
foobar/foobar-bindings.dll
foobar/libfoobar-bindings.dylib
JniPlatform platform = JniPlatform.get(); // e.g. WINDOWS, LINUX
String fileName = platform.mapLibraryName("foobar-bindings"); // e.g. libfoobar-bindings.so
System.load(fileName);

JNI models

Use @JniNative to mark a file as part of a JNI model:

@JniNative(FooBarLibrary.JNI_MODEL)
public final class FooBarLibrary {
    public static final String JNI_MODEL = "foobar/FooBarJNI";
}

Note: @JniNative is an inherited annotation, so you do not need to specify it on classes which extend a class annotated with it. A common pattern for this is:

@JniNative(FooBarLibrary.JNI_MODEL)
public class FooBarNative {
    protected long address;
    
    public FooBarNative(long address) {
        this.address = address;
    }
}

// no JniNative annotation required
public class BazObject extends FooBarNative {
    public BazObject(long address) {
        super(address);
    }
}

Afterwards you can use any of the @Jni- annotations:

Java to C++

Annotate a method as @JniBind to bind a Java method to a native function - in Java 15, you can use multiline strings to include multiple lines:

@JniNative(FooBarLibrary.JNI_MODEL)
public final class FooBarLibrary {
    public static final String JNI_MODEL = "foobar/FooBarJNI";

    public static void init() { _init(); }
    @JniBind("""
            FooBar::preInit();
            FooBar::init();""")
    private static native void _init(); // note: the `_` prefix is automatically removed in generated natives 
}

A common situation is to wrap native objects in memory by creating a Java class which acts as a pointer, by storing a long address which stores the object's address in memory. JniGlue has built-in support for this by annotating the class with @JniTypeMapping([native type]), then using @JniBindSelf with self as a [native type]* (pointer):

class Baz {
    public:
        int mNumber;
}
@JniNative(FooBarLibrary.JNI_MODEL)
@JniTypeMapping("Baz")
public final class Baz {
    private long address;
    
    private Baz(long address) { this.address = address; }
    public static Baz ref(long address) { return address == 0 ? null : new Baz(address); }
    
    public int getNumber() { return _getNumber(address); }
    // `auto* self = (Baz*) _a;`
    @JniBindSelf("return self->mNumber;")
    private static native int _getNumber(long _a); // first argument must be `long _a`
}

C++ to Java

Annotate a class as @JniReferenced to generate a jclass jni_[class name] field, which is automatically found and set to the corresponding Java class on load. You can then annotate (non-native) methods inside as @JniCallback to generate jmethodID jni_[class name]_[method name] fields and JNI_[class name]_[method name](JNIEnv* env, ...) functions to use in your code:

@JniNative(FooBarLibrary.JNI_MODEL)
@JniReferenced
public abstract class LibraryCallback {
    public abstract void onError(ErrorCodeEnum errorCode);
    @JniCallback
    private void _onError(int errorCode) { onError(ErrorCodeEnum.values()[errorCode]); }
}
class LibraryCallbackImpl : LibraryCallback {
    public:
        JNIEnv* env;
        jobject objectGlobalRef;
        
        LibraryCallbackImpl(JNIEnv* env, jobject obj) : env(env), objectGlobalRef(obj) {}
    
        void OnError(int errorCode) override {
            JNI_LibraryCallback_onError(env, objectGlobalRef, errorCode);
        }
}

// ...
    FooBarLibrary::setCallback(new LibraryCallbackImpl(env, object));

Using the generated JNI code

A header file of the generated code will be output in the build/generated/sources/annotationProcessor directory. You can then include this header file in another C++ Gradle subproject to generate a library file from the code:

plugins {
    id("cpp-library")
}

library {
    binaries.configureEach {
        val compileTask = compileTask.get()
        compileTask.dependsOn(":compileJava") // to generate the header file first
        compileTask.includes("${rootProject.buildDir}/generated/sources/annotationProcessor/java/main/foobar/")
    }
}
#include <FooBarJNI.h>

Building from source

git clone https://github.com/aecsocket/jni-glue
cd jni-glue
./gradlew build

jni-glue's People

Contributors

aecsocket avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.