I am trying to bind a native function to Java using JNI RegisterNatives. If the function is in the global scope I can easily bind the function and it works without an issue.
But when I am trying to bind a C++ class member function to Java the callback doesn't get called.
The declaration of my C++ function is like this:
void native_onCall(JNIEnv* env, jobject obj, jint val)
The Java function looks like this.
public native void onCall(int a);
The native function I am trying to bind is in the same class as my RegisterNatives method call. Here is a snippet of how I used a typedef to define the function pointer and added it to JNINativeMethod struct.
typedef void (MyClass::*func_pointer)(JNIEnv*, jobject, jint);
func_pointer cbptr;
JNINativeMethod[index].name = const_cast<char*>("onCall");
JNINativeMethod[index].signature = const_cast<char*>("(I)V");
JNINativeMethod[index].fnPtr = (void*)cbptr;
env->RegisterNatives(jclass, JNINativeMethod, index);
I also used std::bind and a lambda function to bind the function pointer but it doesn't work.
If anyone can point out a way to bind a class member function to java using JNI or what I am doing wrong here it would be really helpful.
Apparently using an instance member function is not the way to go at this.
By using a static function I managed to handle the call inside a class.
Related
I need to call a java class function which returns a map of string as key and a list of class object as value. I am calling java function from c++ using JNI.
I have successfully called the function and stored the returned java map in a JNI 'jobject' variable. Now I need to iterate over elements in map and use their values, but not able to find how to do that.
The structure of java map is like
'Map<String, List<ErrorLogger.ErrorObject>>'
Where ErrorLogger is 'public interface ErrorLogger' and ErrorObject is defined in ErrorLogger as 'public static final class ErrorObject'.
In C++ Code : I am getting this map in jmapobj
//Create Map object
jclass clsMap = env->FindClass("java/util/Map");
jmethodID constructorID = env->GetMethodID(clsMap, "<init>", "()V");
jobject jmapobj = env->NewObject(clsMap, constructorID);
//Call method
jmapobj = env->CallStaticObjectMethod(Cls, method, arg);
Could someone please help me with it.
I have been given a DLL and a JNI wrapper which are used to access a business card scanner.
So far I have only been able to call the API when all classes are in the default package. When I try to move classes to other packages I get an UnsatisfiedLinkError.
I have had no experience of JNI up until now and wonder if I need to rewrite the wrapper of if I can organise the project in a different way. What I cannot do is to use the default package as this would mean putting all my classes there.
The wrapper looks something like this:
public final class Wrapper {
private native int CRTK_Init(int[] lphRTK);
private int m_hRTK;
private int m_hRTKDB;
static
{
System.loadLibrary("crtk_jni");
}
public Wrapper() {
m_hRTKDB = 0;
int[] pRTK = new int[1];
CRTK_Init(pRTK); // UnsatisfiedLinkError here
m_hRTK = pRTK[0];
}
}
The thing with JNI is that the fully qualified class name of the class containing the native methods is tightly coupled to the method-signature of the native (C-)functions.
The C-signature must be something like
JNIEXPORT jobject JNICALL Java_packageName_className_methodName(JNIEnv * env, jclass parameter)
Renaming the class or moving it to another package would change the expected function-name and result in an UnsatisfiedLinkError.
So what can you do?
Unless you have access to the native sources to change the function-names all classes that come as a bundle together with the dll must remain in the default-package, all your own classes can go where you want to have them.
Getting a JNI-package that has its native methods in the default-package is considered poor style and does not bode well for the quality of the received software. And be prepared for further trouble than can come from using the default package, AFAIR e.g. tomcat had (has?) problems with those.
My android project requires some C++/C libraries,and I've got a library (.so) and some headers(.h). and I have reference to some simple demo, using JNI bridge some simple functions, but This lib is complicated for me. How bridging these complex objects and callback.
Created a android project
Copy xxx.so into lib/armeabi, copy all .h files to jni folder.
I want use JNI bridging these c ++ function, I konw I need creat a MStack.h and MStack.cpp to implement these functions, But these headers class makes me very confused,I'm not familiar with C++
some .h like this :
class SIPSTACK_API ISipStack : public Component::IUnknown
{
public:
class IFactory : public Component::IFactoryUnknown
{
public:
virtual ISipStack* create() = 0;
static const char* iid() {return "SipStack";}
};
public:
virtual ~ISipStack(void){}
///#brief
///\param [in] config
///\note
virtual bool setConfig(SipConfigInfo& config)
COMPONENT_UNIMPLEMENTED_OPERATION
///\param [in] handler
///\note
virtual bool start(void)
COMPONENT_UNIMPLEMENTED_OPERATION
///#brief
enum
{
inviteHandler = 0,
actRegHandler,
pasRegHandler,
outCallMsgHandler,
subscribeHandler,
proxyHandler
};
/// #brief
///\param[in] type inviteHandler、registerHandler
///\param[in] handler
///\note
virtual bool attachHandler(int type, Component::IUnknown* handler)
COMPONENT_UNIMPLEMENTED_OPERATION
.....
How can I put these into the corresponding .h and implemented in the cpp. Thanks!
I am trying some things out with JNI and by that I found the following problem:
If I want to use a native function in Java I load the needed lib, in which the needed function is stored, via
static{
System.loadLibrary("lib");
}
and use
native private static int calculate(byte[] numberArray);
to declare the native method in the java file. During the program itself I can use this function to calculate something with:
int result = calculate(array);
This works only if I compiled the shared object with the header-file created by javah so that each function is named on c side as:
static void Java_com_packagename_File_calculate(const void* array, void* result){
code[...]
}
If I delete the reference in the java code ("native [...] calculate[...]")to this c function; is there any possibility to access / execute the still existing c-code via java (of course without editing the exisiting file ;-)) for example via reflections or inheritance? Or is there something possible like:
public class NewClass{
public int nativeCheater(){
System.loadLibrary("lib");
native private static int Java_com_packagename_File_calculate;
}
}
It is important that I want to use a whole new class without any relations to the prior used package com.packagename.(File).
Thanks in advance :-)
No, but you can create a new class with same package and class name and access the same native method. The new class can declare this method public.
An alternative is to use dynamic binding via Jni_OnLoad() and RegisterNatives(). This way, your native implementations may bind to any Java class, or even more than one.
But if you have access neither to the Java class nor to the native source, you can always create your own native method, in your own class, and inside your C explicitly call the original:
static void Java_com_mypackagename_File_calculate(const void* array, void* result) {
Java_com_packagename_File_calculate(array, result);
}
I have a C++ function:
struct Result {
//...
};
bool doSomething(Result[]);
If I use the following JNA binding, the function call works fine:
public class Result extends Structure {
//...
}
public interface CPPLibrary extends Library {
public static final CPPLibrary INSTANCE = (CPPLibrary)Native.loadLibrary("dllname");
boolean doSomething(Result[]);
}
But with direct call, I hit an IllegalArgumentException saying class [Lcom.usta.Result; is not a supported argument type (in method calcPV01 in class com.usta.CPPLibrary). My JNA code for the direct call-mapping:
public class CPPLibrary implements Library {
Native.register("dllname");
public static native boolean doSomething(Result[]);
}
I can see in com.sun.jna.Function#convertArgument() explicitly handles Structure[] but com.sun.jna.Native#getConversion(), which is used by direct call-mapping, does not handle Structure[].
The conversion is trivial, just call Structure.getPointer() on the first element of your structure array (assuming that you got the array from Structure.toArray in the first place).
You're actually better off with that when using direct mapping; when passing non-primitive, non-pointer types the JNI layer has to call back into the VM to derive the appropriate native data.
Feel free to file an issue for support of Structure[] arguments in direct mappings. That should be supported (JNA documentation notes that arrays of Pointer/String/WString/NativeMapped are not supported).
If I use a different method signature:
boolean doSomething(Pointer results);
it does work. But then I have to convert from Result[] to a Pointer my self.