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.
Related
I'm trying to call from C++ into java. I've understood the cux of this answer but I feel I'm not able to achieve the last mile. What classes and methods do I have to use to call Java from C++?
Also not enough points to post comments on there. I basically get that I create the object from java and pass it along in one of my calls into C++. I then get that I could potentially cache it or immedately call into the callback.
This is how my djinni file looks like
my_client_interface = interface +j {
log_string(str: string): bool;
}
get_my_record = interface +c {
static create(): get_my_record;
method_returning_nothing(value: i32);
add_to_string(value: string);
method_returning_something(key: my_record): my_record;
set_callback(cb: my_client_interface);
}
I have no issue creating and passing along the logger callback from java but what concrete class do I call the logger against.
void GetMyRecordImpl::set_callback(const std::shared_ptr<MyClientInterface> & cb)
{
cb->???????
}
since MyClientInterface is still abstract it errors out obviously with
error: member access into incomplete type 'std::__ndk1::shared_ptr<helloworld::MyClientInterface>::element_type' (aka 'helloworld::MyClientInterface')
But if I implement a concrete class against it obviously it's going to call the concrete classes log method and not the one in java. I do see what I need in
bool NativeMyClientInterface::JavaProxy::log_string(const std::string & c_str) {
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeMyClientInterface>::get();
auto jret = jniEnv->CallBooleanMethod(Handle::get().get(), data.method_logString,
::djinni::get(::djinni::String::fromCpp(jniEnv, c_str)));
::djinni::jniExceptionCheck(jniEnv);
return ::djinni::Bool::toCpp(jniEnv, jret);
}
but how would I create the NativeMyClientInterface object needed from the shared_pointer pointing to my abstract class MyClientInterface ?
I wasn't including #include "my_client_interface.hpp" :| the error makes so much sense now.
If you want to use Java object in your C++ code, you got to implement and instantiate that object in Java. Djinni may be perceived as Java Native Interface (JNI) code generator. What you need is Java application, which parts are implemented in C++.
Each interface declared in Djinni is generated for C++ and Java (or Objective-C), so there must be two classes with implementation. One is generated by Djinni and it is a proxy that allows cross-language communication. The other one must be implemented by a programmer.
Regarding your compilation error, I believe you are missing an include directive in the file where GetMyRecordImpl is defined, something like:
#include "generated/MyClientInterface.hpp"
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
env->CallVoidMethod is returning java/lang/Class when using
env->GetObjectClass(aobject); //aobject was the argument sent by JNI to C++
aobject is a Java object that implements an interface.
jobject obj = env->GetObjectClass(aobject)
is supposed to return the Java object but instead is returning java/lang/Class
I encountered this error and had to ask around at work before I got a real answer.
The problem is that when you designate your native method as static, it supplies an instance of the jclass, not a jobject instance of that class, as it's called from a static context. (If you call getCanonicalName() on that jclass, it will return your class's name.)
If the native method needs to be static, then you should pass in the instance as an argument if you need it. Otherwise, just make it not static and you should be all fixed.
You haven't regenerated your .h/.c file since you removed 'static' so your JNI method signature doesn't match the Java one. You have an extra jclass in the argument list that is only there for static methods. So you're going to get some very strange execution.
The answer to my problem was described in "The Java Native Interface - Programmer's Guide and Specification" by Shen Liang.
"You can use Call< Type >Method family of functions to invoke interface methods as well. You must derive the method ID from the interface type"
Firstly regrets if this is a very basic question and i promote that I'm still a code monkey.
I was asked in an interview to elucidate System.out.println();
I explained the following way
//this class belongs to java.lang package
class System{
public static PrintStream out;
}
//this class belongs to java.io package
class PrintStream{
public void println..
}
I've explained that System.out is valid since this is the way we access static variables in java, and out is an object of PrintStream and hence we can access its methods, In sum as
System.out.pritnln();
he asked me to simulate a similar kind of program,i traced and it did not work,since System.out is returning null
my question is where is out object instantiated in java ? Is it a predefined object if I'm not wrong. what should be the meticulous explanation for this.
Technically what should we call out? Is out a variable of type PrintStream type or should one say it as an object of type PrintStream ?
System.out is initialized to null when the class is instantiated. This is set by the nullPrintStream() method in System.java, which just returns null.
When the JVM has initialized, it calls the initializeSystemClass() method. This method calls the native method setOut0() which sets the out variable to the appropriate value.
This may seem weird but it is a necessary operation for the following reasons:
out cannot be set statically to the value because System needs to be one of the first loaded classes (before PrintStream).
out must be final so that its value cannot be directly overridden by a user.
Since out cannot be set statically, and is final, we must override the semantics of the language using a native method, setOut0().
I hope that helps your understanding.
System.out is a normal static attribute, it was set by the JVM through the initializeSystemClass() method during JVM initialization. You can even change it (although it's not recommended) by simply calling System.setOut(printOutStream);, where printOutStream is the stream you want to use as standard output.
Here's a nice article detailing how does System.out.println() work.
System.out is provided by the JVM. By the time your main method is called, System.out is open and ready for use.
See http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#out
In the Oracle Java runtime libraries, it is instantiated natively using the registerNatives() native method which is called (via a static initializer) on loading the System class. This is however an implementation detail.
You can also set System.out directly using System.setOut().
Out in System.out.pritln is a static field (object) of PrintWriter in System class and println is a method of PrintWriter.
Reference :
System : http://docs.oracle.com/javase/6/docs/api/java/lang/System.html
PrintWriter : http://docs.oracle.com/javase/6/docs/api/java/io/PrintWriter.html
There is no need to go for net and documentation even. We can simply say javap java.lang.System this gives you list of all static fields, method prototypes that belong to System class.
We can get details of any java class using javap, provided you know its package and classname
out is public static object of PrintStream defined in System class.
When System class get initialized, it calls its initializeSystemClass() method, here is the code:
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
In this code setOut0() is a native function implemented in System.c:
JNIEXPORT void JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
jfieldID fid =
(*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
if (fid == 0)
return;
(*env)->SetStaticObjectField(env,cla,fid,stream);
}
This is a standard JNI code that sets System.out to the argument passed to it, this method calls the native method setOut0() which sets the out variable to the appropriate value.
System.out is final, it means it cannot be set to something else in initializeSystemClass() but using native code it is possible to modify a final variable.
System.out.println();
here println is an object of printstream class.We can't directly create object for printstream class. Out is an object of system class. out is called field in system class. while calling system.out it indirectly creates object for printstream class. hence we can call println() method using System.out.prontln().
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.