I'd like to start by saying please don't ask me to use the javah tool, I've had more luck writing the few jni function prototypes than getting that tool to work properly.
I know that I am loading my jni libraries properly because they work when I leave the class structure the same.
I have some package name:
package com.bb.me;
public class test {
test2 iTest = null;
public parent test()
{
iTest = new test();
return iTest;
}
//putting my native methods here work just fine
//public native void init();
//etc
}
The c jni function prototype for that above function looks like this:
JNIEXPORT void JNICALL Java_com_bb_me_test_init(JNIEnv* e, jobject i) {}
if I break that above function signature by renaming it inita and call the function I get an error like this:
No implementation found for native Lcom/bb/me/test;.init:()V
if on the other hand I move the native function to the inner class like this:
class test2 extends parent {
//public native void init();
}
and then try to call the same function, jni will complain at me a different way about unimplemented function but this time it looks like this:
No implementation found for native Lcom/bb/me/test$test2;.init:()V
I originally thought if I edited the jni function signature to something like this:
JNIEXPORT void JNICALL Java_com_bb_me_test_test2_init(JNIEnv* e, jobject i) {}
that the function would work but it doesn't seem like that's the case.
What does the "$" dollar sign mean in this jni function signature?
No implementation found for native Lcom/bb/me/test$test2;.init:()V
How can I move the location of this native function and update the jni function signatures without using the javah tool?
I'd like to start by saying please don't ask me to use the javah tool, I've had more luck writing the few jni function prototypes than getting that tool to work properly.
I won't ask you to use javah -- though it's hard not to do -- but I have to at least say that I find that remark surprising. I have found javah very easy to use indeed. If it's not working "properly" for you then I'm inclined to suspect that you have the wrong expectations.
What does the "$" dollar sign mean in this jni function signature?
The $ delimits the simple name of a nested class from the name of the class in which it is nested. This is an aspect of the JVM's internal representation of names, which is what JNI works with.
How can I move the location of this native function and update the jni function signatures without using the javah tool?
You could refer to Oracle's documentation for mapping Java native method names to C function names. The expected native function name is based on the fully-qualified JVM name of the native method's class, on the native method's unqualified name, and, if it's overloaded, on its signature. If you move a native method to a different class then you need to alter the function name to reflect the new location, and it is possible that you will also need to encode the function signature into the name if that was not already done.
The JVM name of your inner class is com/bb/me/test$test2. Supposing that the method is not overloaded, the C function name corresponding to the native method residing in that class would therefore be Java_com_bb_me_test_00024test2_init(). The arguments are a different story -- they depend on the arguments to the Java-side method as well as on whether the native method is static. I do not address them here.
Related
Is it possible to use JNA to check that the signature of the Java interface is consistent with the signature of the associated C funtions?
For example suppose that I have the following C interface for my C code:
__declspec(dllexport) void receive(bool boolValue, int intValue);
And the associated Java interface:
public interface MyLibrary extends Library {
public void receive(int intValue, bool boolValue);
}
If I load the library, I will have no problem, but of course I will have an error if calling the receive method of the interface because the signature of the method is not aligned with the signature of the corresponding function.
Is there any way to know that the alignment is off before calling the method? I though about using:
Function function = NativeLibrary.getFunction("receive");
But after that it seems that I have no way to know anything about the signature of the function.
No, there is no automated mechanism, and in fact incorrectly mapping types is probably the most common error made when implementing JNA mappings, and that's usually the very first thing I check when code misbehaves.
If JNA can't find a matching function with the same number of arguments, you'll get an error:
java.lang.UnsatisfiedLinkError: Error looking up function 'Foo': The specified procedure could not be found.
If the method name matches the native function, and the number of arguments matches, JNA will not give any obvious indication of an improper mapping, however if you write robust unit tests and attempt to obtain sane/expected output from the native function, this will help catch most errors (although "catch" means "displays odd symptoms.")
You still may miss platform-dependent errors such as 32- vs. 64-bit long or pointer types.
There are still cases where it is technically impossible to know the correct mapping for a compiled library where the byte width of some types depends on compile-time switches, such as for the off_t type. There is no foolproof way of determining this at run time.
There are countless of articles and questions about how to call Java code from C++ using JNI, and I can do that, I can call some Java function from C++.
Now what I cannot find any information on is the following:
Assume I have a Java function which requires a callback function passed to it. This callback function is called at some later point in time from a different thread.
Now I want to call this function from a C++ program, and once the callback function is called, I want a C++ callback to be called. Can anybody point me to a source with information on how to do that?
Background is I want to use a Java library inside an existing C++ project (all on Linux, though I doubt this is relevant). The overhead for calling Java functions through JNI is not an issue here.
You are right, somehow the documentation for this is not found easily.
But I still remember from a former project the way I did this.
You will have to do your part by reading some freely available online documentation because I might miss some details. I will give you the links at the end of this post.
So if I understand you correct, you want to call a native C++ function from Java.
First of all remember the Java Native Interface is not C++ but C.
This is like most native interfaces of higher level programming languages (all I have ever seen so far).
Create your Java view of the native interface. That is create a Java class and declare native methods. There is the keyword native you can use for that. You do not provide any implementation just declare it.
Use javac -h to generate native header files. Read the docs of that tool. In Java 7 there was a seperate tool for that called javah. But with current Java 11 you should use javac.
Use C or C++ to provide an implementation for the functions declared in the generated headers. Compile and link them to a shared object (*.so or *.dll).
At runtime of your java application load your native code from your new library by calling:
System.load("path-to-lib");
You do not have to do that last step 4 if your native function is already loaded in the current process. That would be if you are embedding a Java app in a CPP application. In that case you might want to look at RegisterNatives.
The documentation for Java keyword native:
Java Keyword native
The documentation of JNI is here:
Java 11 JNI Spec
Also look at the documentation of the Java Compiler for how to generate native headers. Look for the option -h:
JavaC
.
Edit
Somehow I understand your question today better than yesterday:
You have a C++ application that embeds a Java app.
From C++ you want to invoke a Java method.
When invoking you want to pass a callback method.
When the Java method is done it must call that callback method you passed it before.
Ok, together with what you already know and plus the explanation I gave above this can be done.
It actually can be done again in different ways.
I will explain a simple one:
Your C++ app already knows which callback needs to be called when the Java method is finished.
When you call the Java method you give it the callback as a key.
You already know how to invoke a Java method from C++.
This key can be anything. To keep it simple the key is a uintptr_t, an integer of the size of your pointers.
In that case we just pass the function pointer as a callback to the Java method.
But Java cannot invoke the callback by dereferencing that integer/pointer thing.
Now you invoke a native extern "C" function and give it that key as parameter.
I explained above how to invoke a native function from Java.
That native function now just needs to cast that integer back to a pointer:
(reinterpret_cast<>()) and invoke your callback.
Of course the native function can accept additional parameters than the key to the callback, if there is some data you want to pass to your callback.
I think the idea is now very clear.
If you want to have more portable code then do not use the address of the callback as key.
Rather use an integer or even string and use a std::map to map that key to your real callback.
But just start with that simple example. And when that is working it is easy to improve it.
Most work will be setting up the project and tools to work together.
Alright, here for future readers how I managed to do it. There's a few points which don't seem perfectly clean to me, if anybody has an idea on how to do it more cleanly, I'll be very interested in this.
So, I wrote a simple Java class Bar in package foo, which is to be called from C++, passing a reference to a function (more on that below) and calling the function with some hardcoded parameters.
package foo;
import foo.Functor;
//this is just what we want to call from C++
//for demonstration, expect return type int
public class Bar
{
public static void run(long addr) {
Functor F = new Functor(addr);
//synchronously here, just to prove the concept
F.run(1,2);
}
}
As you see, I also wrote a class Functor, which also straightforward
package foo;
//we need to write this for every signature of a callback function
//we'll do this as a void foo(int,int), just to demonstrate
//if someone knows how to write this in a general (yet JNI-compatible) way,
//keeping in mind what we are doing in the non-Java part, feel free to tell me
public class Functor
{
static {
System.loadLibrary("functors");
}
public native void runFunctor(long addr,int a,int b);
long address;
public Functor(long addr)
{
address = addr;
}
public void run(int a, int b) {
runFunctor(address,a,b);
}
}
This depends on a shared library I called functors. Implemented very straightforward. The idea is to keep the actual logic separate, and just provide the interface in the shared object. The main drawback, as mentioned before, is that I have to write it for every signature, I see no way to template this.
Just for completeness, here's the implementation of the shared object:
#include <functional>
#include "include/foo_Functor.h"
JNIEXPORT void JNICALL Java_foo_Functor_runFunctor
(JNIEnv *env, jobject obj, jlong address, jint a, jint b)
{
//make sure long is the right size
static_assert(sizeof(jlong)==sizeof(std::function<void(int,int)>*),"Pointer size doesn't match");
//this is ugly, if someone has a better idea...
(*reinterpret_cast<std::function<void(int,int)>*>(address))(static_cast<int>(a),static_cast<int>(b));
}
And finally, here's how I call it in C++, defining the callback function during runtime, outside the shared object:
#include <iostream>
#include <string>
#include <jni.h>
#include <functional>
int main()
{
//this is from some tutorial, nothing special
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=."; //this is actually annoying, JNI has this as char* without const, resulting in a warning since this is illegal in C++ (from C++11)
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
delete[] options;
if (rc != JNI_OK)
return EXIT_FAILURE;
jclass cls = env->FindClass("foo/Bar");
jmethodID mid = env->GetStaticMethodID(cls, "run", "(J)V");
//the main drawback of this approach is that this std::function object must never go out of scope as long as the callback could be fired
std::function<void(int,int)> F([](int a, int b){std::cout << a+b << std::endl;});
//this is a brutal cast, is there any better option?
long address = reinterpret_cast<long>(&F);
env->CallStaticVoidMethod(cls,mid,static_cast<jlong>(address));
if (env->ExceptionOccurred())
env->ExceptionDescribe();
jvm->DestroyJavaVM();
return EXIT_SUCCESS;
}
This works perfectly fine, and I can work with this. Though, a few things are still bothering me:
I have to write the interface (both a Java class and the corresponding C++ implementation) for each signature of functions I want to pass. Can this be done in a more general way? My feeling is Java (and especially JNI) isn't flexible enough for this.
The reinterpret_casts for converting the pointer to std::function to an integer and back are not something I like doing. But it was the best way I could think of to pass a reference to a function (which possibly exists only during run time) to Java...
In the initialization of the Java VM in C++, I'm setting an option which in the JVM interface is defined as char * (there should be a const here). This looks like a very innocent line, but gives a compiler warning, since it is illegal in C++ (it is legal in C, that's why JNI developers likely didn't care). I found no elegant way around this. I know ways how to make it legal, but I really don't want to write several lines of code just for this (or throw around const_casts), so I decided, for this, just to live with the warning.
I have a third-party VB.Net dll that I want to call from Java.
The VB.Net dll has the following signature (pseudo code, but feels like Java...):
class MyClass1 {
public Object method1(StringRef arg1, StringRef arg2) {
// do something here...
return someResult;
}
}
class MyClass2 {
public Object method2(StringRef arg1, StringRef arg2) {
// do something here...
return someOtherResult;
}
}
Note: StringRef is my way of saying the method expects me to pass in strings by reference.
I am trying to call this dll object from within Java. Using JNA, I have the following:
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface DllName extends Library {
DllName INSTANCE = (DllName)Native.loadLibrary("DllName", DllName.class);
public static interface MyClass1 {
public Object method1(String arg1, String arg2);
}
public static interface MyClass2 {
public Object method2(String arg1, String arg2);
}
}
The INSTANCE object here loads just fine. However, I cannot figure out what structure the body of DllName should take to map to the dll's class, method signature. Also, I have not seen how I might call Native in a way that would load the object directly. For example, if I do:
DllName INSTANCE = (DllName)Native.loadLibrary("DllName.MyClass1", DllName.class);
This results in an UnsatisfiedLinkError since the dll is named DllName. Making this call requires a different interface than shown above.
Questions:
Is this even possible? E.g. Can I call a VB.Net dll from Java using JNA given the structure above.
What structure does DllName need to have to properly map to the class MyClass1 and MyClass2? This is my core question here.
In the DllName.MyClass1 call above, is there some alternative way?
Did I miss anything with any of the alternative items mentioned below? Perhaps some other solution I missed?
I have explored the following alternatives:
Reviewed this article, but did not see an example that matches my structure. I also looked at the unit tests referenced on the bottom.
Creating a C++ wrapper, as suggested here /questions/1556421/use-jni-instead-of-jna-to-call-native-code (I'd post as a link, but not enough reputation with SO...). I haven't actually tried this, as I am not familiar with C++. I would expect too-much head-banging, when I think some change to my Java code would suffice.
JNI: This seems like it is only for C/C++ type dlls.
javOnet: Almost works, but the VB.Net methods expect strings by reference, which is not currently supported by javOnet. I reported the issue to them, and I expect a fix. Even if it did work, it seems like a JNA solution should work. There is also a cost issue with that solution.
jni4net: This does not work for me since this is a third-party dll. jni4net expects some hook on the .Net side.
Please let me know if you would like me to add any additional color here.
javOnet already provides support for arguments passed by ref or out since version 1.2. You can read more at:
http://www.javonet.com/quick-start-guide/#Passing_arguments_by_reference_with_ref_and_out_keywrods
You must wrap you JAVA type in "AtomicReference" so it can be updated within the method call and your JAVA variable let's say integer will be automatically modified on .NET side. You can see the usage sample below:
NObject refEx = Javonet.New("RefExample");
//Wrap Java integer in AtomicReference to allow passing by reference
AtomicReference<Integer> myInt = new AtomicReference<Integer>(10);
refEx.invoke("Method",new NRef(myInt));
System.out.println(myInt.get());
//Output will display number "55" because int passed by reference has been modified within the method body.
How can I pass Parameters to Main via JNI?
Currently I load my DLL like:
class SharedLibrary {
native void GetBuffer(ByteBuffer Buffer);;
SharedLibrary(String[] exec_args) {
String path = new File(exec_args[0]).getAbsolutePath();
System.load(path); //Load My DLL. I want to Pass this DLL some arguments.
ByteBuffer Foo = ByteBuffer.allocateDirect(.....);
GetBuffer(Foo);
}
}
How can I pass the DLL arguments? I need to pass multiple arguments.
The purpose of loading a library into Java is to fulfill Java methods which are declared with the native attribute, such as native void methodname(_arguments go here_);. You can declare one or more native methods in a class, but all of them are expected to be defined (using JNI standards) in your DLL. From Java, you call them like any other method (by using whatever arguments are defined for the method).
If there are data elements you want the DLL's initialization entry point to receive, you need to make them static members (or methods) of some class and the DLL needs to know to access that class to get them. This, however, would be quite abnormal and is probably not the best way to perform whatever it is you're looking to do.
Well, if you need "multiple parameters", any existing "dll main" won't work for you. You are most probably referring to WinAPI DllMain and you probably think that this function is mandatory to any DLL, much the same way as every C executable is expected to have main() function. It is not. JNI in particular has JNI_OnLoad which doesn't take any parameters, but so DllMain doesn't have any user-definable "multiple parameters" per your requirement. If you need your own parameters, why can't you create an initialization method? Even the DllMain doc is recommending that. DllMain is very limited in what it can do. Make the JNI init method static, so that you can call it before instantiating the SharedLibrary object in Java. What's the problem with it? Tell something about the "multiple parameters" you need so much.
I'm attempting to call native methods within a 3rd party DLL, which has a C interface with methods such as:
DWORD ExampleInterfaceMethod( DWORD Mode, LPSTR Header );
I've successfully loaded the DLL using:
System.loadLibrary("DLLName");
and I've created a method:
protected native int ExampleInterfaceMethod(int type, int Nth, byte[] name);
This method doesn't seem to be using the correct variable types, as whenever I call it the following error is thrown: java.lang.UnsatisfiedLinkError: com.DLLTest.ExampleInterfaceMethod(II[B)I
What variable types do I need to use in Java in order to call this method, or am I missing something else?
With JNI, you need specially-named C functions to implement your Java native methods. You can't simply add a native method to call an existing C function - instead the normal way is creating a "wrapper" C function which calls the existing one, and is named the right way.
You might want to have a look at JNA. This is a wrapper around JNI which allows you to call C functions from the Java side without manually writing adapting native code for this.