In java, what does the private static method registerNatives() of the Object class do?
The other answers are technically correct, but not very useful for someone with no JNI experience. :-)
Normally, in order for the JVM to find your native functions, they have to be named a certain way. e.g., for java.lang.Object.registerNatives, the corresponding C function is named Java_java_lang_Object_registerNatives. By using registerNatives (or rather, the JNI function RegisterNatives), you can name your C functions whatever you want.
Here's the associated C code (from OpenJDK 6):
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
(Notice that Object.getClass is not in the list; it will still be called by the "standard" name of Java_java_lang_Object_getClass.) For the functions listed, the associated C functions are as listed in that table, which is handier than writing a bunch of forwarding functions.
Registering native functions is also useful if you are embedding Java in your C program and want to link to functions within the application itself (as opposed to within a shared library), or the functions being used aren't otherwise "exported", since these would not normally be found by the standard method lookup mechanism. Registering native functions can also be used to "rebind" a native method to another C function (useful if your program supports dynamically loading and unloading modules, for example).
I encourage everybody to read the JNI book, which talks about this and much more. :-)
What might be slightly confusing is that the code shown for java.lang.Object.registerNatives in a previous answer is just an example of how to register native functions. This is the code that (in the implementation of OpenJDK) registers native functions for class Object. To register native functions for your own class, you must call the JNI function RegisterNatives from the native code in your own library. This might sound a bit circular, but there are a couple ways to break the loop.
Follow the example of this implementation of class Object:
a. In your Java class, declare a native method (preferably static) named registerNatives (or any other name. it doesn't matter).
b. In your native code, define a function named Java_<your fully qualified class name>_registerNatives, which contains a call to the JNI function RegisterNatives.
c. Make sure that in your Java code, your Java registerNatives method is called prior to any calls to other native methods.
OR
Use JNI_OnLoad
a. In your native library define a function jint JNI_OnLoad(JavaVM *vm, void *reserved). In the body of this function, call the JNI function RegisterNatives.
b. The Java VM will automatically look for and call JNI_OnLoad when your native library is loaded by System.loadLibrary, which you should already be calling, probably in a static initializer for your class. (You get the required env pointer by calling the GetEnv function in the table that the vm pointer points to.)
It is used on such scene :
C or C++ work as host, and Java the JVM as client. (C load jvm.dll and use JNI_CreateJavaVM to create a JVM)
When java code need to call host's C function,
If you still use jni dll (System.loadLibrary("foo.dll");) to bind the native java method, the memory space of dll is not the same as C host. (It still works if the function you called is host state irrelevant, but you cannot access host's state values in this way)
Here you need to use env->RegisterNatives() at host to inject(bind,expose,export) host's C functions to the JVM.
Related
I would like to implement an entire Java class via JNI, but I have only been able to find information about implementing methods, not classes themselves. In every example I've found, the JNI part is always just a bunch of functions.
I have a C++ class that I want to port to Java. I tried following some tutorials but failed. It doesn't seem to work for classes.
I have run into numerous problems; just one example would be what to do with the constructor of the class.
Problems are Example: what do i do with the constructor of the class.
You can keep the pointer of the inner Native class in a Java class member with long type.
In order to call the constructor of native class in Java class constructor, you can define a separate native method which allocates a native object and keep the resulting pointer in your Java class long type member.
With the example below, you can see a simple Java wrapper class and its JNI implementation which illustrates how to call construct and call inner native pointer:
public class JavaClassName {
private long nHandle;
protected JavaClassName() {
nHandle = ConstructNativeHandle();
}
public native void SomeMethodJava();
}
and jni implementation:
JNIEXPORT long JNICALL Java_packageName_JavaClassName_ConstructNativeHandle
(JNIEnv *env, jobject obj)
{
NativeClassName * pNativeObject = new NativeClassName();
return (jlong)pNativeObject;
}
JNIEXPORT void JNICALL Java_packageName_JavaClassName_SomeMethodJava
(JNIEnv * env, jobject obj)
{
jclass c = env->GetObjectClass(obj);
// J is the type signature for long:
jfieldID fid_handle = env->GetFieldID(c, "nHandle", "J");
NativeClassName * nativeObject = (NativeClassName *) env->GetLongField(obj, fid_handle);
nativeObject->SomeMethodNative();
return;
}
The reason you have been unable to find the information you are looking for is that it does not exist. JNI is primarily a mechanism for implementing Java native methods in C or C++, and secondarily a mechanism for embedding Java in C or C++. To serve those purposes it provides means for native code to access and manipulate Java objects, but it was never intended to allow Java classes themselves to be implemented in native code, and it makes no provision for that.
You can create a Java class whose methods are all native, and you can use such a class to wrap your C++ class (instances will each retain a pointer to an instance of the native class, most likely as a Java long), but you cannot compile native code into a Java class.
There are tools that can help with this sort of thing. First on my list to consider would be SWIG.
I've got some C functions which I am calling through JNI which take a pointer to a structure, and some other functions which will allocate/free a pointer to the same type of structure so that it is a bit easier to deal with my wrapper. Surprisingly, the JNI documentation says very little about how to deal with C structures.
My C header file looks like so:
typedef struct _MyStruct {
float member;
} MyStruct;
MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
The corresponding JNI C wrapper file contains:
JNIEXPORT jobject JNICALL
Java_com_myorg_MyJavaClass_createNewMyStruct(JNIEnv *env, jobject this) {
return createNewMyStruct();
}
JNIEXPORT void JNICALL
Java_com_myorg_MyJavaClass_processData(JNIEnv *env, jobject this, jintArray data,
jint numObjects, jobject arguments) {
int *actualData = (*env)->GetIntArrayElements(env, data, NULL);
processData(actualData, numObjects, arguments);
(*env)->ReleaseIntArrayElements(env, data, actualData, NULL);
}
...and finally, the corresponding Java class:
public class MyJavaClass {
static { System.loadLibrary("MyJniLibrary"); }
private native MyStruct createNewMyStruct();
private native void processData(int[] data, int numObjects, MyStruct arguments);
private class MyStruct {
float member;
}
public void test() {
MyStruct foo = createNewMyStruct();
foo.member = 3.14159f;
int[] testData = new int[10];
processData(testData, 10, foo);
}
}
Unfortunately, this code crashes the JVM right after hitting createNewMyStruct(). I'm a bit new to JNI and have no idea what the problem could be.
Edit: I should note that the C code is very vanilla C, is well-tested and was ported from a working iPhone project. Also, this project is using the Android NDK framework, which lets you run native C code from an Android project from within JNI. However, I don't think that this is strictly an NDK issue... it seems like a JNI setup/initialization error on my part.
You need to create a Java class with the same members as C struct, and 'map' them in the C code via methods env->GetIntField, env->SetIntField, env->GetFloatField, env->SetFloatField, and so on - in short, lots of manual labor, hopefully there already exist programs that do it automatically: JNAerator (http://code.google.com/p/jnaerator) and SWIG (http://www.swig.org/). Both have their pros and cons, the choice is up to you.
It's crashing because Java_com_myorg_MyJavaClass_createNewMyStruct is declared to return jobject, but is actually returning struct MyStruct. If you ran this with CheckJNI enabled, the VM would complain loudly and abort. Your processData() function is also going to be fairly upset about what it gets handed in arguments.
A jobject is an object on the managed heap. It can have extra stuff before or after the declared fields, and the fields don't have to be laid out in memory in any particular order. So you can't map a C struct on top of a Java class.
The most straightforward way to deal with this was identified in an earlier answer: manipulate the jobject with JNI functions. Allocate the objects from Java or with NewObject, Get/Set the object fields with appropriate calls.
There are various ways to "cheat" here. For example, you could include a byte[] in your Java object that holds sizeof(struct MyStruct) bytes and then use GetByteArrayElements to get a pointer to it. A bit ugly, especially if you want to access the fields from the Java side as well.
C structure is the collection of variables (some are function pointer). Pass to java is not a good idea. In general, it is the problem how to pass more complex type to java, like pointer.
In JNI book, to keep the pointer/structure in native and export manipulation to java is recommended. You can read some useful articles. The JavaTM Native Interface Programmer's Guide and Specification, I have read. 9.5 Peer Classes have a solution to deal with it.
Make the class on both the Java and C++ sides, just putting in the member variables. C++ structs are really just classes with public data members. If you are really in pure C, stop reading now.
Use your IDE(s) to make setters and getters for the member variables automatically.
Use javah to generate the C header file from the Java class.
Do some editing on the C++ side to make the setters and getters match the generated header file.
Put in the JNI code.
This is not an ideal solution, but it may save you a little time, and it will at least give you a skeleton that you can edit. This functionality could be added to an IDE, but without a big demand, it probably won't happen. Most IDEs don't even support mixed language projects, let alone having them talk to each other.
I have class in C++ which must response for HTTP connection, that class must establish connection, send responses and do some other functions. This class is a part of huge project which I compile and finally get .so library for Android.
class HTTPSClient
{
public:
WinHTTPSClient();
~WinHTTPSClient();
bool Connect(const XMLString& a_strURL);
};
Now I want to call java functions from Connect function in c++. I have experiences in calling java functions from C++ code, but I always pass JavaVM to the class for example I call init(JavaVM* javaVm); and give as an argument javavm which comes from native code.
Now my question is: Can I call java method from C++ code without passing as an argument any JavaVm.
Define the JavaVM as a global/static variable of some class, e.g., by wrapping it up as a singleton. The variable can be accessed without explicitly passing it as an argument.
You can use the Java Invocation API to create a VM directly in your native code.
Jim S.
I'm currently using both C++ and Java in a project and I'd like to be able to send an object which is contained in C++ to my Java interface in order to modify it via a GUI and then send the modification back in C++.
So far I've been returning either nothing, an int or a boolean to Java via the JNI interface. This time I have to send an object through the interface. I have made similar class definition available both in C++ and in Java. I'd like to know how I'd go about creating the object so that I can use it in Java.
In C++ I have:
JNIEXPORT MyObject JNICALL Java_ca_X_Y_Z_C_1getMyObject(JNIEnv* env, jclass, jint number);
This function would get called by Java in order to get the object from the C++ side (the object is contained in a singleton, easily accessible).
On the Java end, I do a simple call to this method,
MyObject anObject = C_getMyObject(3);
which should return me the newly created object.
Java currently returns me a UnsatisfiedLinkError when I do the actual call. What is wrong?
Here's the solution I opted to use:
First, I would create a similar object in Java. Then, from C++ I would instanciate it and pass it all the values.
(C++)
clazz = env->FindClass("java/lang/Integer");
jmethodID method = env->GetMethodID(clazz, "<init>", "(I)V");
return env->NewObject(clazz, method, (jint)anInteger);
But then I realised this wasn't very portable and was a bit too complicated.
Instead, I decided to return a string that Java would parse and use to initialize the object on its side.
(JAVA)
String aString = "valuesoftheobject";
MyObject myObject(aString);
MyObject would have a constructor which takes a string. I believe the solution is simple and effective.
Another tool you should look at is SWIG. SWIG is a great tool for generate wrappers in other languages (such as Java, Python or C#) for existing C/C++ objects. It will generate automatic Java wrappers around C/C++ objects, and do all the heavy JNI lifting for you.
I use it extensively in Xuggler. To see an example, if you download the Xuggler source code there is a C++ object here:
csrc/com/xuggle/xuggler/IStreamCoder.h
I define a SWIG interface file here:
csrc/com/xuggle/xuggler/IStreamCoder.i
And when run through Swig it generates a Java object (which is stored here)
generate/java/com/xuggle/xuggler/IStreamCoder.java
We can then access that object from Java easily (well, I add some ref counting stuff, but that's pretty advanced). Hope that helps.
Art
If your MyObject class is defined in C++, you're not going to be able access its methods in Java. I'd try to define a Java wrapper class around your C object:
Java:
public C_Object() {
handle = createHandle();
}
private native long createHandle(); // or whatever pointer/handle type?
public void doStuff() {
_doStuff(handle);
}
private native void _doStuff(long handle);
If you can extrapolate a C api instead, you might try JNA.
Your UnsatisfiedLinkError may be the extra character in your function name as written above, or perhaps it can't handle the MyObject return value?
In java, what does the private static method registerNatives() of the Object class do?
The other answers are technically correct, but not very useful for someone with no JNI experience. :-)
Normally, in order for the JVM to find your native functions, they have to be named a certain way. e.g., for java.lang.Object.registerNatives, the corresponding C function is named Java_java_lang_Object_registerNatives. By using registerNatives (or rather, the JNI function RegisterNatives), you can name your C functions whatever you want.
Here's the associated C code (from OpenJDK 6):
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
(Notice that Object.getClass is not in the list; it will still be called by the "standard" name of Java_java_lang_Object_getClass.) For the functions listed, the associated C functions are as listed in that table, which is handier than writing a bunch of forwarding functions.
Registering native functions is also useful if you are embedding Java in your C program and want to link to functions within the application itself (as opposed to within a shared library), or the functions being used aren't otherwise "exported", since these would not normally be found by the standard method lookup mechanism. Registering native functions can also be used to "rebind" a native method to another C function (useful if your program supports dynamically loading and unloading modules, for example).
I encourage everybody to read the JNI book, which talks about this and much more. :-)
What might be slightly confusing is that the code shown for java.lang.Object.registerNatives in a previous answer is just an example of how to register native functions. This is the code that (in the implementation of OpenJDK) registers native functions for class Object. To register native functions for your own class, you must call the JNI function RegisterNatives from the native code in your own library. This might sound a bit circular, but there are a couple ways to break the loop.
Follow the example of this implementation of class Object:
a. In your Java class, declare a native method (preferably static) named registerNatives (or any other name. it doesn't matter).
b. In your native code, define a function named Java_<your fully qualified class name>_registerNatives, which contains a call to the JNI function RegisterNatives.
c. Make sure that in your Java code, your Java registerNatives method is called prior to any calls to other native methods.
OR
Use JNI_OnLoad
a. In your native library define a function jint JNI_OnLoad(JavaVM *vm, void *reserved). In the body of this function, call the JNI function RegisterNatives.
b. The Java VM will automatically look for and call JNI_OnLoad when your native library is loaded by System.loadLibrary, which you should already be calling, probably in a static initializer for your class. (You get the required env pointer by calling the GetEnv function in the table that the vm pointer points to.)
It is used on such scene :
C or C++ work as host, and Java the JVM as client. (C load jvm.dll and use JNI_CreateJavaVM to create a JVM)
When java code need to call host's C function,
If you still use jni dll (System.loadLibrary("foo.dll");) to bind the native java method, the memory space of dll is not the same as C host. (It still works if the function you called is host state irrelevant, but you cannot access host's state values in this way)
Here you need to use env->RegisterNatives() at host to inject(bind,expose,export) host's C functions to the JVM.