34

Using JNI can we pass custom data types from Java to C (or vice versa)? I see a mapping of primitive datatypes to types in C however not too sure if we can send across our own data types (e.g. Send across or return an Employee object or something!).

user277460
  • 341
  • 1
  • 3
  • 3
  • You can use [JNA](https://github.com/twall/jna/) to easily pass structures around. JNA allows you to write your binding completely in Java code. :-) – C. K. Young Mar 23 '10 at 23:52
  • You can. If you want to make Java/C translation easier, check out [Swig](http://www.swig.org/), which allows you to translate [between Java and C/C++ structures](http://www.swig.org/Doc1.3/Java.html) in a straightforward fashion.. – Brian Agnew Mar 23 '10 at 23:26
  • https://www.baeldung.com/jni#2-using-objects-and-calling-java-methods-from-native-code – Leponzo Jul 05 '21 at 18:41

1 Answers1

75

If you're going to be doing this with a lot of objects, something like Swig would be best. You could use jobject type to pass around custom objects. The syntax isn't nice, perhaps there is a better way to write this.

Example Employee object:

public class Employee {
    private int age;

    public Employee(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

Call this code from some client:

public class Client {
    public Client() {
        Employee emp = new Employee(32);

        System.out.println("Pass employee to C and get age back: "+getAgeC(emp));

        Employee emp2 = createWithAge(23);

        System.out.println("Get employee object from C: "+emp2.getAge());
    }

    public native int getAgeC(Employee emp);
    public native Employee createWithAge(int age);
}

You could have JNI functions like this for passing an employee object from Java to C, as a jobject method argument:

JNIEXPORT jint JNICALL Java_Client_getAgeC(JNIEnv *env, jobject callingObject, jobject employeeObject) {
    jclass employeeClass = (*env)->GetObjectClass(env, employeeObject);
    jmethodID midGetAge = (*env)->GetMethodID(env, employeeClass, "getAge", "()I");
    int age =  (*env)->CallIntMethod(env, employeeObject, midGetAge);
    return age;
}

Passing an employee object back from C to Java as a jobject, you could use:

JNIEXPORT jobject JNICALL Java_Client_createWithAge(JNIEnv *env, jobject callingObject, jint age) {
    jclass employeeClass = (*env)->FindClass(env,"LEmployee;");
    jmethodID midConstructor = (*env)->GetMethodID(env, employeeClass, "<init>", "(I)V");
    jobject employeeObject = (*env)->NewObject(env, employeeClass, midConstructor, age);
    return employeeObject;
}
mateuscb
  • 10,150
  • 3
  • 52
  • 76
Stew
  • 1,901
  • 10
  • 9
  • 3
    I have problems with "LEmployee;" part I tried with "com.pak1.Employee" and with "Lcom.pak.Employee;" but no result, any ideas ? – Lukap Oct 09 '13 at 10:27
  • 2
    @Lukap: if your class is com.pak.Employee then the signature of the class will be "Lcom/pak/Employee;" – nautilusvn Jul 06 '14 at 10:26
  • 1
    @mafioso you can create an object of class "Ljava/lang/string;". Commenting for completeness, doubt you actually still need this... – Nepho Nov 03 '17 at 12:27
  • The `jclass proc_jclass = env->FindClass(“Lcom/my/class/JavaClass”);` method needs to be called at the FIRST LINE of your `JNI` function or else you may experience `ClassNotFoundExceptions`. Also, this did not work for me with the semi-colon in the class path. Once I removed the semi-colon from the classpath string, it worked. This is a Great answer! – Sakiboy Jan 28 '19 at 20:24
  • 1
    swig is too complex and hard to use. – Yugy May 17 '21 at 15:54