Skip to content
Advertisement

Calling a Java variadic function from C through the JNI

I am currently working on creating some Java bindings for a C library I work on. One of our C-structs has a char buffer that is a file system path. After calling the C function, the buffer is correctly populated. I want to take the buffer and convert it to a java.nio.file.Path member on the Java object.

I am having some trouble however. I for some reason am generating a NullPointerException within C, and I can’t really see the problem.

The way to create a java.nio.file.Path object is going through java.nio.file.Paths::get().

Here is the relevant C code:

const jclass paths_class = (*env)->FindClass(env, "java/nio/file/Paths");
if ((*env)->ExceptionCheck(env))
    return;
const jmethodID get_method = (*env)->GetStaticMethodID(
    env, paths_class, "get", "(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;");
if ((*env)->ExceptionCheck(env))
    return;
const jstring path_str = (*env)->NewStringUTF(env, info.mi_path);
if ((*env)->ExceptionCheck(env))
    return;
const jobject path_obj =
   (*env)->CallStaticObjectMethod(env, paths_class, get_method, path_str); // exception generated here
if ((*env)->ExceptionCheck(env))
    return;

And the Java class for good measure:

public final class MclassInfo {
    private native void _get(final Kvdb kvdb, Mclass mclass) throws HseException;

    private long allocatedBytes;
    private long usedBytes;
    private Path path;

    MclassInfo(final Kvdb kvdb, final Mclass mclass) throws HseException {
        _get(kvdb, mclass);
    }

    public long getAllocatedBytes() {
        return allocatedBytes;
    }

    public long getUsedBytes() {
        return usedBytes;
    }

    public Path getPath() {
        return path;
    }
}

All I can think is that somehow I am not calling the Java variadic function properly. I have also tried passing NULL as an extra argument to the method call, but ended up with the same issue.

Advertisement

Answer

The method you are trying to invoke is declared as get(String first, String... more). The variadic syntax in Java is just sugar for an array of the specified type, i.e. the two arguments of this method are really String and String[] — which you correctly coded in the GetStaticMethodID call as (Ljava/lang/String;[Ljava/lang/String;).

So to call it you need two arguments: one String and one String[] (array) — and (for your case) the array must contain zero elements, but such an empty array is not the same as NULL. Have a gander at NewObjectArray.

Advertisement