Unable to invoke Java API with ArrayList object from JNI - java

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.

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().

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

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.

JNI / JNA Unsatisfied Link, but symbol is present

i am trying to integrate a legacy system via a provided c-library "libext.so".
To test JNA/JNI i want to call the "setProperty" function.
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
this is my code, using java 8, jna 4.5.1 and/or native jni, both ways fail with an UnsatisfiedLinkError when calling the function - loading the library works without an Exception.
public class TestClass
{
static {
try {
System.load("/path/to/libext.so");
} catch (Throwable e) {
e.printStackTrace();
}
}
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(("/path/to/libext.so"), CLibrary.class);
void setProperty(String key, String value);
}
public static native synchronized void setProperty(String key, String value);
public static void main(String[] args) {
// setProperty("a", "b");
CLibrary.INSTANCE.setProperty("a", "b");
}
}
what am i missing?
#Update:
I now moved both, the JNI class and the JNA INterface to the correct package and renamed the jna interface
package com.company;
public interface LibExtLibrary extends Library {
LibExtLibrary INSTANCE = (LibExtLibrary)
Native.loadLibrary(("/path/to/libext.so"),
LibExtLibrary.class);
void Java_com_company_ExtClass_setProperty(String key, String value);
void Java_ExtClass_setProperty(String key, String value);
void ExtClass_setProperty(String key, String value);
void setProperty(String key, String value);
}
calling the first two methods on INSTANCE gives an InvalidMemoryAccess, the second two an UnsatisfiedLinkError.
The JNI Method worked, as soon as the fully qualified classname was equal to the one defined in the native library
If the question is "why can't I call JNI methods with JNA?":
To be able to call external libraries from Java you have to use JNI. You declare some methods as native and javah will generate special functions for you that you can fill in with your code. Every function will have two additional arguments: an env pointer that is bound to the calling Java thread and the object or class that is the method receiver. If you pass a Java object as one of the other arguments you will get a jobject in your function.
If the implementation of the JNI functions would only consist of forwarding the calls to another external library you can also use JNA. JNA uses JNI to wrap libffi so you can call an existing external library directly. This way you don't have to create a wrapper library yourself. JNA will not create an env pointer or pass the method receiver as argument. And it will try to marshal all the other arguments into something the external library understands. That means no jobjects here.
Summary: JNI calls functions explicitly created for it and the arguments are Java specific. JNA uses JNI internally to call functions in non-Java external libraries.

Can java get method with methodname through reflections

I know Java can get Method Object using the Reflection.getMethod(...) method,but the method needs method parameter types。 but I don't know the exact parameter type。e.g.
byte a = 20;
System.out.println(a);
the println method hasn't the overload method println(Byte),but has println(Int)。
How to get the println method through the byte type?
the other example
class MyClass
{
}
class MyClass1 extends MyClass
{
}
class TestClass
{
public static void method1(MyClass c)
{
... ...
}
}
TestClass.method1(new MyClass1()) is correct.but can i get the method1 through parameter type MyClass1 ?
Class.getMethods will get all method in Class, too much。 can i get all overload method same name?
java.lang.Class (see JavaDoc) provides two ways of finding methods:
Method getMethod(String name, Class<?>... parameterTypes)
and
Method[] getMethods()
(and corresponding getDeclaredMethod() variants).
So there's no API in the standard Java library for directly getting what you need - you'll need to get all methods, filter the ones with the right name, then inspect the parameter types.
Or you may be able to find a 3rd-party library that will do this for you. For example, the reflections library has a getMethodsMatchParams(Class<?>... types) method.
The jOOR library also provides various methods for finding methods with "similar" signatures.

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