pass C++ object from C++ to Java as function argument - java

I'd like to pass C++ object from C++ to Java as function argument. I use SWIG to generate Java bindings for my class definition(named "MyObj"). I use the following method(env is a JNIEnv*),
env->CallStaticVoidMethod(cls, mid, my_obj);
where "cls" corresponds to a class I get via "env->FindClass" and "mid" points to a static method of it. When I run the program, however, in that method("mid") I found that my argument is just a null pointer.
I also tried to use (jobject)(&my_obj) but it also doesn't work. Did I miss something? Thanks so much!

Related

JNI function error in android

I'm in trouble with this: http://imgur.com/hH0q3Tn
I'm using the VTK sample code and JNI isn't working and I don't know what to do. I compiled all the libraries and when I try the app on phone, the app stop.
What can I do?
Edit: Errors: http://pastebin.com/rf7vFVT8
The second arg for static native method should be jclass, not jobject.
See Are native Java methods equivalent to static Java methods? for more details.
Native Method Arguments
The JNI interface pointer is the first argument to native methods. The JNI interface pointer is of type JNIEnv. The second argument differs depending on whether the native method is static or nonstatic. The second argument to a nonstatic native method is a reference to the object. The second argument to a static native method is a reference to its Java class.
I solved.
The building of the library was incorrect and I followed this guide http://www.vtk.org/Wiki/VTK/Building/Linux

Calling java method from c++ code, without passing any JavaVm

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.

How to use Rhino to bridge a Java class that contains overloaded methods and is indexable in JavaScript?

In porting a C# project to Java that uses JavaScript for user scripts, there's a class that has an overloaded method:
public class TreeNode {
public TreeNode GetChild(int index) { ... }
public TreeNode GetChild(String childName) { ... }
public TreeNode GetChild(String targetAttributeName, String targetAttributeValue) { ... }
...
}
Using Rhino, I can bridge this object between Java and JavaScript with:
ScriptableObject.putProperty(scope, "TreeNode", Context.javaToJS(new TreeNode(), scope));
This works great for scripts that simply make calls to the functions (and all the overloaded functions get resolved to the correct type correctly). However, the C# application also indexes into the TreeNode. For example, a JavaScript user function is:
function NumericButtonClick() {
screen = TreeNode.FindNodeById("Screen");
screen["Text"] = screen["Text"] + Source["Text"];
}
Running this JavaScript code results in the expected Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EvaluatorException: Java class "TreeNode" has no public instance field or method named "Text".
To fix this, Rhino supports this by allowing you implement the Scriptable interface (or extend the ScriptableObject which contains a bunch of common boilerplate code). After doing that, the binding seemingly disappears:
Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object.
Debugging the code, the specific interaction is that Rhino makes four calls to the get() method of Scriptable:
get(name = "FindNodeByID")
get(name = "__noSuckMethod__")
get(name = "toString")
get(name = "valueOf")
To fix this, we can create specific FunctionObject objects to let Rhino know FindNodeByID is a function to some piece of Java code. (While I've tried doing it manually, just using Scriptable.defineFunctionProperties does this automatically in a lot less code.) This works well until we reach the overloaded GetChild functions, when we get this exception:
org.mozilla.javascript.EvaluatorException: Method "GetChild" occurs multiple times in class "TreeNode".
Alternatively, ScriptableObject.defineClass(scope, TreeNode.class) will map jsFunction_* functions into JaavScript. However, this generates the same sort of error:
org.mozilla.javascript.EvaluatorException: Invalid method "jsFunction_GetChild": name "GetChild" is already in use.
Finally, I looked at adding logic inside the get() to try and pick which FunctionObject we want and return in to Rhino. However, you're not provided any parametrization of the function or any way to look forward except in a very hacky, cumbersome way.
Am I missing something? Is there any way to both index into a mapped Java object in Rhino and have overloaded Java functions? Rhino clearly supports them both, and surely supports them together, but it doesn't seem obvious how to do it.
Thanks for any ideas!
I had to do something similar and came across this question while I was trying to figure out how to do it.
There is a solution provided for variable argument methods using the ScriptableObject.defineClass/jsFunction_ approach you mention in your question. It is demonstrated in the Foo.java example included with the rhino distribution as:
public static Object jsFunction_varargs(Context cx, Scriptable thisObj, Object[] args, Function funObj)
Note that the method signature has match the above, so it must be static, so you would have:
public static Object jsFunction_GetChild(Context cx, Scriptable thisObj, Object[] args, Function funObj)
In the body of jsFunction_GetChild, you'll have to inspect args to decide which version of GetChild to call. In my case, I have a variable number of args so I was able to just check args.length. In your case, it looks like you'll have to check the types. Then, inside your switching logic you can cast the thisObj parameter to the type of your class (since your method has to be static, you need to use the passed in reference to make the call) in order to call and return the value from the right GetChild.

JNI and static interface

Is JNI's "method signature" different if method is defined to return (static) interface ?
In my Java class I have this method:
public SharedPreferences.Editor getSharedPrefsEditor() {
return mActivity.getPreferences(Context.MODE_PRIVATE).edit();
}
SharedPreferences.Editor is a static interface in SharedPreferences.
In my C++ JNI code I do this:
// 'env' is the java environment that JNI passes to us
// 'jObject' is the one that JNI passes to us (along with env)
jclass javaCallerClass = env->GetObjectClass(jObject);
jmethodID methodId_getSharedPrefsEditor = env->GetMethodID(
javaCallerClass,
"getSharedPrefsEditor",
"()Landroid/content/SharedPreferences/Editor;");
For some odd reason, this doesn't work. It compiles, but at runtime I get this:
DEBUG/dalvikvm(19020): GetMethodID:
method not found:
Lcom/mangotaster/madballs/MyRenderer;.getSharedPrefsEditor:()Landroid/content/SharedPreferences/Editor;
I'm calling other methods in that class in pretty much the same way without any problems.
The only change seems to be the return value.
I did try to call the edit() function straight from JNI code, but got the same error - which makes me believe that my function signature "()Landroid/content/SharedPreferences/Editor;" is indeed wrong.
More info on the SharedPreferences class.
Nested/Inner classes don't use the standard namespace nomenclature in JNI signatures. The inner class is actually translated to a normal class at the same level as the outer class by the Java compiler with the name "Outer$Inner". I think you want "()Landroid/content/SharedPreferences$Editor;".
No need to guess about this, or ask on forums ;-) javap -s will tell you the correct JNI signature string for any Java method.

Returning a C++ class to Java via JNI

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?

Categories