I am trying to use a public interface in a .dll file in JAVA. This is what a public interface in the .dll shows:
// Interface declaration.
public interface ISslTcpClient
{
string Encrypt(string requestContent);
string Decrypt(string requestContent);
};
Here is how I load my dll and use it in my Java application in eclipse:
public class NJInew {
static {
System.loadLibrary("ICVTnsClient");
}
native String Encrypt(String requestContent);
public static void main(String[] args) {
NJInew p= new NJInew ();
p.Encrypt("pejman");
}
}
However I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: NJInew.Encrypt(Ljava/lang/String;)Ljava/lang/String;
at NJInew.Encrypt(Native Method)
at NJInew.main(NJInew.java:13)
Please let me know how to fix this issue and I would greatly appreciate it.
I do not understand how the native DLL can possibly look like a Java interface. Are you sure it's a JNI DLL? You can't call any old DLL from Java. If it isn't a JNI DLL you'll either need to add the required JNI entry points to it, starting with the javah tool, or write a wrapper DLL that contains those and calls this one.
This interface looks definitely like written in .NET C#. Therefore you do not need to call native DLL but managed .NET DLL and that is completely different topic.
You can achieve it yourself by wrapping .NET DLL with native C++ code and calling it from JAVA but number of obstacles and challenges is huge... You need to take care of type conversion, memory management, threads, C++ runtime depndencies and more... so that approach is not recommended.
What you should look for is native bridge like Javonet which takes care of all those things for you and makes sure you can run your code on any machine.
Using your interface would like like this:
Javonet.addReference("ICVTnsClient.dll");
NObject client = Javonet.New("SslTcpClient");
//some concreto type which implements this interface
String encryptedStr = client.invoke("Encrypt", "some string");
You can get free license for academic and non-commercial usage or try the free trial: http://www.javonet.com
Related
I want to call node js function from java:
here is my hello.js javascript code:
function myFun(param)
{
console.log("hello"+param);
}
here is my java code:
public static void main(String[] args) throws IOException {
Process process = new ProcessBuilder("C:\\Program Files\\nodejs\\node.exe","hello.js").start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
With this java code i am able to execute hello.js file but i want to call myFun function and set the parameters in this function from java code .. is it possible to do this.
You can use GraalVM to call node.js function from java.
GraalVM offers you a polyglot runtime and the distribution includes both a JDK and a node.
You can execute JavaScript from Java, embedding the JavaScript context in your Java program, like this:
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
static String JS_CODE = "(function myFun(param){console.log('hello '+param);})";
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value value = context.eval("js", JS_CODE);
value.execute(args[0]);
}
}
}
Note the () wrapping the function definition, I just want it to return the function immediately there. You can use other ways too, not just code in String too, Files, modules, etc.
And run it with GraalVM on the PATH:
❯ javac HelloPolyglot.java
❯ java HelloPolyglot StackOverflow
Hello Java!
hello StackOverflow
While it's not strictly necessary for this question, here's the Javadoc for the Value class so you can use the polyglot values.
This way you can use JavaScript. It won't have the platform capabilities node.js offers like the node event loop, fs access, etc, node is a separate platform and it's tricky to embed that into a JVM process.
What you can do -- is start the node process, which will start the JVM.
Imagine you have an app like app.js
var HelloPolyglot = Java.type("HelloPolyglot");
HelloPolyglot.main(["from node.js"]);
console.log("done");
You can then run (with GraalVM node):
❯ node --jvm --vm.cp=. app.js
Hello Java!
hello from node.js
done
Note that we pass --jvm to start it with the JVM (otherwise there'll be no capabiltiy to do Java), and pass the classpath of the Java program to the node so it knows how to start the JVM properly.
Both node and JVM then run in the same process, and the interop works using the same Value classes as above.
It's not that easy. You have a few possible methods to do that:
Use JNI-Bindings to V8 (Node.js is just V8 with a big library and some glue).
Use ProcessBuilder and pass the arguments.
(It's not exactly what you asked for) Use a Javascript-Engine written in Java (GraalVM)
Pros/Cons
Has the advantage, that it may give you a lot of control (==>More flexible), but writing JNI is hard, error-prone and time-consuming.
is the most simple solution, but not that flexible.
is maybe another solution, that can be superior to 1. (No need to ship native libraries) and 2. (Very fragile, as you need a specific location for node.exe).
I would suggest looking into https://github.com/caoccao/Javet, it allows you to embed a node.js runtime into a java application.
I am writing a wrapper class for C++ ".so". I want to use the library in Java application and Android app using JNI. So I have to create header file and cpp file which will do JNI calls.
I could use that on Linux in Java application.
The steps I followed:
Created java class and called native functions in that class
public class TestWrapper {
static {
System.load("/home/native.so");
}
public static void main(String[] args) {
new TestWrapper().TestWrapper();
}
private native void sayHello();
}
Created header file and cpp file. CCP contains following code
JNIEXPORT void JNICALL Java_TestWrapper_sayHello(JNIEnv *, jobject){
uint16_t data = 0;
void (*func_print_name)(const uint16_t*);
void* handle = dlopen("libCppTobeUsed.so.0", RTLD_LAZY);
if (handle){
*(void**)(&func_print_name) = dlsym(handle, function_name);
func_print_name(&data);
dlclose(handle);
std::cout << "data received .." << data << std::endl;
}
}
}
Compiled this cpp class and generated "native.so"
This is working fine. The "native.so" could call the fuction form "ibCppTobeUsed.so.0" when called from TestWrapper.java.
I want to use same library for android as well. So, I have to write wrapper class all over again in Android NDK? Or I can compile my "native.so" for Android platform?
If I try to use it directly, I get error
"install_failed_no_matching_abis".
No, you cannot use the same shared library. Android is not GNU. You need to compile your libraries for Android.
So, I have to write wrapper class all over again in Android NDK?
No, you can write it in a way that works for both. You need to factor our your JNI wrapper class from your main class, since Android uses Activity instead of main.
I would also strongly recommend against ever relying on dlclose on any platform. The API is not sound, and will lead to surprising behavior with modern C++. A single global thread_local with a non-trivial destructor renders the library un-unloadable, so the next dlopen will not reset library state as you might expect. If you need to implement initialization/finalization logic for your library, make explicit Initialize and Finalize functions a part of the libary and call them directly.
Without knowing your architecture's full architecture I can't be sure, but from the sample you've given here I'd recommend dropping the dlopen/dlsym from your JNI entirely and just link against libCppTobeUsed directly.
I try to write a wrapper for the CDRip library. But I'm very new in JNI. I have a problem to get a native method to work:
public class CDRipJNI {
static {
System.loadLibrary("CDRip");
}
// Get the DLL version number
static native int CR_GetCDRipVersion();
}
In another class I call this method:
int version = CDRipJNI.CR_GetCDRipVersion();
The dll is loaded successfully but the method call fails:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.test.CDRipJNI.CR_GetCDRipVersion()J
at com.test.CDRipJNI.CR_GetCDRipVersion(Native Method)
at Test.main(Test.java:5)
If it doesn't have a method with that signature, which it doesn't, either your Java class is wrong or it isn't a JNI DLL at all.
If it is a JNI DLL, I don't know why you would have to write any kind of wrapper for it at all: they should provide it.
So it isn't. And if it isn't a JNI DLL, you wil have to write your own JNI DLL that calls it, and that matches your Java class, etc. etc. as per usual JNI.
Edit 2 After recieving a response from Mathworks support I've answered the question myself. In brief, there is an options class MWComponentOptions that is passed to the exported class when instantiated. This can, among other things, specify unique print streams for error output and regular output (i.e. from disp()-liked functions). Thanks for all the responses none the less :)
====================================================================
Just a quick question - is there any way to prevent MATLAB code from outputting to the Java console with disp (and similar) functions once compiled? What is useful debugging information in MATLAB quickly becomes annoying extra text in the Java logs.
The compilation tool I'm using is MATLAB Compiler (which I think is not the same as MATLAB Builder JA, but I might be wrong). I can't find any good documentation on the mcc command so am not sure if there are any options for this.
Of course if this is impossible and a direct consequence of the compiler converting all MATLAB code to its Java equivalent then that's completely understandable.
Thanks in advance
Edit This will also be useful to handle error reporting on the Java side alone - currently all MATLAB errors are sent to the console regardless of whether they are caught or not.
The isdeployed function returns true if run in a deployed application (with e.g. MATLAB Compiler or Builder JA) and false when running in live MATLAB.
You can surround your disp statements with an if isdeployed block.
I heard back from a request to Mathworks support, and they provided the following solution:
When creating whatever class has been exported, you can specify an MWComponentOptions object. This is poorly documented in R2012b, but for what I wanted the following example would work:
MWComponentOptions options = new MWComponentOptions();
PrintStream o = new PrintStream(new File("MATLAB log.log"));
options.setPrintStream(o); // send all standard dips() output to a log file
// the following ignores all error output (this will be caught by Java exception handling anyway)
options.setErrorStream((java.io.PrintStream)null);
// instantiate and use the exported class
myClass obj = new myClass(options);
obj.myMatlabFunction();
// etc...
Update
In case anyone does want to suppress all output, casing null to java.io.PrintStream ended up causing a NullPointerException in deployment. A better way to suppress all output is use to create a dummy print stream, something like:
PrintStream dummy = new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
Then use
options.setErrorStream(dummy);
Hope this helps :)
Another possible hack if you have a stand-alone application and don't want to bother with classes at all:
Use evalc and deploy your func name during compile:
function my_wrap()
evalc('my_orig_func(''input_var'')');
end
And compile like
mcc -m my_wrap my_orig_func <...>
Well, it is obviously yet another hack.
The task is to call method from an existing dll.
I'm trying to do that on an example of CopyFileA from kernel32.dll.
The method signature is:
Function long CopyFileA(String lpExistingFileName, String lpNewFileName, boolean bFailifExists) Library "kernel32"
This is how I'm trying to do this in java:
public class Test {
static {
System.loadLibrary("D:\\test\\kernel32");
}
public static void main(String[] args) {
(new Test()).CopyFileA("D:\\test\\hi.txt", "D:\\other\\hi.txt", false);
}
public native long CopyFileA(String lpExistingFileName, String lpNewFileName, boolean bFailifExists);
}
I'm getting:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.CopyFileA(Ljava/lang/String;Ljava/lang/String;Z)J
All manuals that I've found describes examples when you write C code and then create dll for yourself. So, you implement native method with signature from generated header file.
But here we already have a dll.
Thanks!
The examples you have seen are the best way to go. There is some harness code that needs to be done to enable Java to call into a native method and visa-versa. With out this harness code there is no way for either of them to communicate with each other.
If you are desperate to call CopyFileA then create the harness code in some C/C++ code that then calls CopyFileA.
If you are trying to avoid programming in C/C++ then there is no way for your java to communicate with CopyFileA.
There may be a third party code that may help you. I don't know of any.
This is really simple: everything you need is download jna.jar file and include it into your project.
Bellow I put some code snippet how to solve your task:
Function showWindow = Function.getFunction("kernel32", "CopyFileA");
Object[] params = new Object[3];
params[0] = "D:\\test\\hi.txt";
params[1] = "D:\\other\\hi.txt";
params[2] = false;
Object result = showWindow.invoke(params);