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"
Related
I want to know what the modern C++11 equivalent of Java's instanceof. I have seen this SO post but it is quite old and was wondering if there's a more modern, better solution in C++11?
I was hoping there's a possibility of using a switch construct without having to resort to a manual enum class.
class A {
};
class B : public A {
}
class C : public A {
}
on_event(A& obj)
{
switch (obj) {
case A:
case B:
case C:
}
}
My base class does not have any virtual methods or functions. I am representing an expression tree for a parser and the base class is just a polymorphic holder - like an ADT in Haskell/OCaml.
The same answer still applies, and has always been like this in C++:
if (C * p = dynamic_cast<C *>(&obj))
{
// The type of obj is or is derived from C
}
else
{
// obj is not a C
}
This construction requires A to be polymorphic, i.e. to have virtual member functions.
Also note that this behaviour is different from comparing typeid(obj) == typeid(C), since the latter tests for exact type identity, whereas the dynamic cast, as well as Java's instanceof, only test for the target type to be a base class of the type of the most-derived object.
In C++ plain old data (POD) has no runtime type information. The classes described all take exactly 1 byte, and have identical runtime representations in any compiler with the empty base class optimization.
As such what you want cannot be done.
Adding a virtual destructor to the base class adds in RTTI, and dynamic_cast support.
Adding an enum or int field to the base that gets initialized differently for each derived class also works.
Yet another option is to create a template function, and store a pointer to it, like so:
using my_type_id=void(*)();
template<class>void get_my_type_id_helper(){};
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;}
and then storing a my_type_id in A initialized appropriately. This is reinventing RTTI, and as you want more features you will approach C++ RTTI overhead.
In C++ you only pay for what you ask for: you can ask for classes without RTTI, which you did, and get it.
RTTI is Run Time Type Information. POD is plain old data, a C++03 term. Many classes are not POD: the easy way is to add a virtual destructor. C++11 has more fine grained standard layout and aggregate terms.
Technically RTTI and POD are not opposites of each other: there are classes with no RTTI that are not POD.
Note that MSVC has options to not generate RTTI and its aggressive Comdat folding can break the manual RTTI I did above, in both cases in violation of the standard.
Maybe you are interested in the answer I've posted inside your mentioned old SO post.
https://stackoverflow.com/a/49296405/1266588
The answer presents an implementation of instanceof without the usage of dynamic_cast based on C++11, template metaprogramming and RTTI. A small performance measurement application demonstrates that it is more efficient than dynamic_cast if you use compiler optimization.
Don't do that. In most cases you should review your design when you ask for instanceof or dynamic_cast.
Why? You are most likely violating Liskov's substitiontin principle.
How about this approach:
class A {
public:
virtual void action();
virtual ~A();
};
class B : public A {
public: void action() override;
};
class C : public A {
public: void action() override;
};
void on_event(A& obj)
{
obj.action();
}
Note that as #Yakk pointed out you need at least one virtual method anyway to get dynamic polymorphism. And there is a rule that says: When you have at least one virtual method, always also write a virtual destructor in the base class.
You can do all this with templates and specialization or type tagging but I take from your question -- coming from Java -- you don't want to go there yet. You really like virtual methods, don't you? Sorry, that you have to mark them in C++.
If you're willing to limit yourself to types known at compile-time (rather than working through pointers on instances of classes with vtables) - then C++11 and later does have an instanceof equivalent: It is std::is_base_of.
You might also want to check out std::is_convertible and std::is_same.
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.
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.
I'm coming from the world of c#.
in C# i am able to use the class dynamic http://msdn.microsoft.com/en-us/library/dd264741.aspx
This allows me to not have to use templated/generic classes but achieve a simliar feel for certian situations.
I'm have been unsuccessfull in internet searchs as unfortunately 'dynamic' and 'java' keywords turn up alot of unrelated infromation on dynamic architectures.
I have dabbled a bit in javaFX and there is a type var which appears to have the same usage as c#'s dynamic. However it doesnt appear to be usable in Java.
thanks,
stephanie
Java doesn't support dynamic typing, but you can simulate something like that using dynamic proxy in Java. First you'll need to declare an interface with operations you want to invoke on your objects:
public interface MyOps {
void foo();
void boo();
}
Then create Proxy for dynamic invocation on myObjectInstance:
MyOps p = (MyOps) Proxy.newProxyInstance(getClass().getClassLoader(), //
new Class<?>[] { MyOps.class }, //
new MyHandler(myObject));
p.foo();
p.boo();
where MyHandler is declared like this:
public class MyHandler implements InvocationHandler {
private final Object o;
public MyHandler(Object o) {
this.o = o;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Method method = o.getClass().getMethod(m.getName(), m.getParameterTypes());
return method.invoke(o, args);
}
}
so, if myObject has methods foo() and boo(), they will be invoked, or else, you'll get a RuntimeException.
There is also number of languages that can run in JVM support dynamic typing, e.g. Scala, Groovy, JRuby, BeanShell, JavaScript/Rhino and many others. There is some JVM changes are coming in Java 7 to support a native dynamic dispatch, so these languages could perform much better, but such feature won't be directly exposed in statically typed Java language.
There is nothing like that in Java
There's nothing equivalent in Java. The closest thing you could do is declare a variable of type Object but then you have to cast that variable to whatever you're expecting in order to invoke any method on it that's not implemented by Object (or use reflection but that's sloooow).
Java is a strongly typed language. I think for the next version there will be some dynamic typing, to allow for closures, but that's next year or more probably 2012.
In Groovy you can just use "def" to declare a variable without a type, and the type will be resolved at runtime. And you can compile the Groovy code to Java bytecode...
You can also include Scala code, which does not require explicit type declarations. Scala produces Java byte code. I haven't used C#, so I'm afraid I can't take this comment to the point of responding directly to the question. Maybe someone else can add to it.
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?