How to use java map (java/util/Map) in C++ using JNI - java

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.

Related

Accessing C# Object in java as method parameter using jni4net

We are able to call java in C# code and able to pass Strings and integers as method parameters. Able to access Strings are integers directly by using java java.lang.String and java.lang.Integer with out issues.
But when we pass C# custom object as method parameter we could not find a way to access it.
Eg: Employee.cs is the C# class with parameter name.
Used proxygen to create EmployeeLibraray.dll, EmployeeLibraray.j4n.dll and EmployeeLibraray.j4n.
C# code where we are trying to pass C# object
var bs = new BridgeSetup();
bs.AddAllJarsClassPath("./");
Bridge.CreateJVM(bs);
Bridge.RegisterAssembly(typeof(JavaTest).Assembly);
JavaTest obj = new JavaTest(); ================================> JavaTest
is the class generated using proxygen where it is called in C#
EmployeeLibraray.Employee e = new EmployeeLibraray.Employee();
===========> Custom C# object to be passed to Java
e.LoginName = "test";
obj.execute( e);
Code in java
public void execute(system.Object inputObj) throws Exception {
}
Question
How should we cast the inputObj as Employee so that can access directly e.getName().

Binding a C++ class member function to Java using JNI

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.

Loading a static void C function via AndroidfromJNI another Package

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);
}

Unable to invoke Java API with ArrayList object from JNI

I am trying to call a Java API that accepts ArraList of Strings from JNI
/*My Java Method that needs to be called from JNI*/
public void postArrayListOfStringsToJavaFromJNI(ArrayList<String> list)
{
}
//I am trying to create the methodId like below in JNI to call my Java API postArrayListOfStringsToJavaFromJNI
jmethodID method_id = env->GetMethodID(dmrcallbacks, "postArrayListOfStringsToJavaFromJNI", "(Ljava/lang/Object;)V");
But I am getting an error
11-22 23:22:45.130: E/AndroidRuntime(19189): java.lang.NoSuchMethodError: no method with name='postArrayListOfStringsToJavaFromJNI' signature='(Ljava/lang/Object;)V' in class Lcom/example/JavaSample;
Is there any problem with the GetMethodID call that is having "(Ljava/lang/Object;)V" as first parameter for calling the Java API with parameter "ArrayList"
(Ljava/lang/Object;)V is the signature of a void method taking a single parameter of type java.lang.Object, you presumably need (Ljava/util/ArrayList;)V instead.

JNA direct call not working with argument Structure[]

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.

Categories

Resources