JNI Java <-> native Struct

  • StructPass.java
class StructPass
{
    public native void toNativeStruct();
    public native void fromNativeStruct();
    public native void initNative();

    private String name;
    private int age;
    private float height;

    static {
        System.loadLibrary("jni");
    }

    public StructPass(String n, int a, float h)
    {
        name = n;
        age = a;
        height = h;
    }

    public static void main(String[] args)
    {
        StructPass hello = new StructPass(new String("kerker"), 10, 180);
        hello.initNative();
        hello.toNativeStruct();
        hello.fromNativeStruct();
        System.out.println("In Java:");
        System.out.println("  hello.name = \"" + hello.name + "\"");
        System.out.println("  hello.age = "  + hello.age);
        System.out.println("  hello.height = " + hello.height);
    }
}

編譯 java

javac StructPass.java

產生 jni header

javah -jni  StructPass
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class StructPass */

#ifndef _Included_StructPass
#define _Included_StructPass
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     StructPass
 * Method:    toNativeStruct
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_StructPass_toNativeStruct
  (JNIEnv *, jobject);

/*
 * Class:     StructPass
 * Method:    fromNativeStruct
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_StructPass_fromNativeStruct
  (JNIEnv *, jobject);

/*
 * Class:     StructPass
 * Method:    initNative
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_StructPass_initNative
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
#include "StructPass.h"
/* Header for class StructPass */

static struct {
    jfieldID name;
    jfieldID age;
    jfieldID height;
} gStructPassClassInfo;


JNIEXPORT void JNICALL Java_StructPass_toNativeStruct
(JNIEnv* env, jobject obj)
{
    jstring jstr;
    int age;
    float height;
    const char* str;

    /* Get a reference to obj's class */
    printf("In C:\n");

    /* Read the instance field name */
    jstr = (jstring)(*env)->GetObjectField(env, obj, gStructPassClassInfo.name);
    str = (*env)->GetStringUTFChars(env, jstr, NULL);

    age = (*env)->GetIntField(env, obj, gStructPassClassInfo.age);
    height = (*env)->GetFloatField(env, obj, gStructPassClassInfo.height);

    if (str == NULL) {
        return; /* out of memory */
    }

    printf("  c.name = \"%s\"\n", str);
    printf("  c.age = %d\n", age);
    printf("  c.height = %f\n", height);
    (*env)->ReleaseStringUTFChars(env, jstr, str);

}

JNIEXPORT void JNICALL Java_StructPass_fromNativeStruct
(JNIEnv* env, jobject obj)
{
    jstring jstr;

    /* Create a new string and overwrite the instance field */
    jstr = (*env)->NewStringUTF(env, "123");

    (*env)->SetObjectField(env, obj, gStructPassClassInfo.name, jstr);
    (*env)->SetIntField(env, obj, gStructPassClassInfo.age, 18);
    (*env)->SetFloatField(env, obj, gStructPassClassInfo.height, 179.0);
}

JNIEXPORT void JNICALL Java_StructPass_initNative
(JNIEnv* env, jobject obj)
{
    /* Get a reference to obj's class */
    jclass cls = (*env)->GetObjectClass(env, obj);

    gStructPassClassInfo.name = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
    gStructPassClassInfo.age = (*env)->GetFieldID(env, cls, "age", "I");
    gStructPassClassInfo.height = (*env)->GetFieldID(env, cls, "height", "F");
}
gcc -fPIC -Wall -I /usr/lib/jvm/java-8-openjdk-amd64/include/ -I /usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -shared -o libjni.so StructPass.c

Run

java -Djava.library.path=. StructPass
In C:
  c.name = "kerker"
  c.age = 10
  c.height = 180.000000
In Java:
  hello.name = "123"
  hello.age = 18
  hello.height = 179.0