System.out.println() stops working after JNA/DLL call? - java

I have multiple System.out.println() calls in my program. My issue is that, after making a call to a DLL through a JNA Library (which does work without returning an error code or throwing an exception), subsequent calls to println() execute without printing anything! I know that the statements are executing because I'm stepping through them in NetBeans!
Unfortunately, I don't have a clue about the C code behind the DLL, and I guess you won't be able to duplicate this unless you register with qimaging.com and download the QCam SDK. I'm just wondering if anyone has experienced anything similar to this System.out.println() behavior, i.e. that it works until a certain point, then stops printing even though it executes.
This is my main test class:
package hwi.scope;
import com.sun.jna.ptr.IntByReference;
import hwi.scope.qcam.QCamDriverX64;
import java.io.File;
/**
* QCamTest class tests some functions of the QCam driver library.
* #author rnagel
*/
public class QCamTest
{
private static QCamDriverX64 driver;
// Main test method:
public static void main() throws Exception
{
// Set path to easily find DLL in the /dll folder:
File f = new File("dll");
System.setProperty("jna.library.path", f.getCanonicalPath());
// Use JNA to load the driver library:
driver = QCamDriverX64.INSTANCE;
// Load camera driver from the library:
loadQCamDriver();
// Print out the driver version:
printQCamVersion();
}
// Load camera driver method:
public static void loadQCamDriver()
{
System.out.println("Loading QCam driver..."); // Executes and prints to console
int error = driver.QCam_LoadDriver();
System.out.println("Done loading driver."); // Executes, but doesn't print to console
}
// Print camera driver version:
public static void printQCamVersion()
{
// Obtain driver version as a combination of 'major' and 'minor' increments:
IntByReference major = new IntByReference(), minor = new IntByReference();
int error = driver.QCam_Version(major, minor);
// At this point, I've verified that I have a obtained a valid version.
System.out.println("QCam v." + major.getValue() + "." + minor.getValue()); // Executes, but doesn't print to console
}
}
And this is the QCamDriverX64 class that I've made to wrap the DLL:
package hwi.scope.qcam;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
/**
* QCamDriverX64 wraps the 64-bit version of the QCam driver DLL.
* #author rnagel
*/
public interface QCamDriverX64 extends Library {
// Make the library name publicly accessible:
public static final String DLL_NAME = "QCamDriverx64";
// Load an instance of the library using JNA:
public static final QCamDriverX64 INSTANCE = (QCamDriverX64) Native.loadLibrary(DLL_NAME, QCamDriverX64.class);
// Load the QCam driver:
int QCam_LoadDriver();
// Obtain QCam driver version # (in major and minor increments)
int QCam_Version (IntByReference major, IntByReference minor);
}
I'm using NetBeans 8.2 and JDK 1.8.0_121.
Thanks for taking a look! I'd appreciate any insight!

You can easily reproduce that by calling
System.out.close();
System.err.close();
I'm assuming that the native code in the DLL is doing something in that respect. It might be friendly by actually doing above call. In that case you could save System.out and System.err into variables, set some dummy streams with System.setOut() and System.setErr() and put everything back as it was before after the DLL-call. If the native code closes the underlying file handles, that won't help and the only option is to file a bug report at the provider of the DLL.

Related

How to accept and execute arbitrary Java code

Many Websites allow a user to type in Java code and run it. How does a program accept Java written externally/at run time and run it?
The only/closest answer i see on StackOverflow is from 5 years ago about Android development that recommended using Janino (Compile and execute arbitrary Java string in Android). Is this still the way to go? Has a better approach (like something built into Java) appeared in the last half decade?
If it helps, I'm building a training app for my students. The code is short (a few methods, maybe 20 lines max) and they must use standard libraries (no need to worry about importing things from maven, etc.).
Like similar online coding sites, I'd like to return the output of the run (or compilation failure).
An example use case:
Webpage says "The code below has an error, try to fix it." A text box contains code. A semicolon is missing.
User modifies the code and presses submit.
The Webpage either returns a compile error message or success.
Another use case would be for me to execute unit tests on the code they submitted and return the result. The point being, I give the user feedback on the code compilation/run.
Here is a small example to use the Java compiler interface
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class Compiler {
public static void main(String[] args) throws Exception {
// compile the java file
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "D:\\development\\snippets\\Test.java");
System.out.println("compiler result " + result);
// load the new class
File classesDir = new File("D:\\development\\snippets\\");
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { classesDir.toURI().toURL() });
Class<?> cls = Class.forName("Test", true, classLoader);
// invoke a method of the class via reflection
Object instance = cls.getDeclaredConstructors()[0].newInstance();
Method testMethod = cls.getMethod("test");
String testMethodResult = (String) testMethod.invoke(instance);
System.out.println(testMethodResult);
}
}
And here the test class
public class Test {
public String test() {
return "String from test.";
}
}
Running the Compiler class returns
compiler result 0
String from test.

Using VC++ dll using JNA

I am using a BTICARD.DLL, which is the dll of Arinc429 card. I need to write wrapper class in Java for the functions like BTICard_CardOpen for example.
I Had written an interface below BTICardAPI.java:
package NLIPjt;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.Native;
// import com.sun.jna.ptr.IntByReference;
import com.sun.jna.Pointer;
public interface BTICardAPI extends StdCallLibrary {
BTICardAPI INSTANCE = (BTICardAPI) Native.loadLibrary("BTICARD", BTICardAPI.class);
int BTICard_CardOpen(Pointer LPHCARD, int cardnum);
}
and my Java implementation prog
BTICardTest.java:
package NLIPjt;
// import com.sun.jna.ptr.IntByReference;
import com.sun.jna.Pointer;
public class BTICardTest {
public static void main(String args[]) {
BTICardAPI BTI1 = BTICardAPI.INSTANCE;
int iErr;
int CardNo = 0;
Pointer CardHandle = null;
iErr = BTI1.BTICard_CardOpen(CardHandle, CardNo);
System.out.println("Error Value: " + iErr);
}
}
i get the following error in netbeans IDE:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'BTICard_CardOpen': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:245)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:566)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:542)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:528)
at com.sun.jna.Library$Handler.invoke(Library.java:228)
at com.sun.proxy.$Proxy0.BTICard_CardOpen(Unknown Source)
at NLIPjt.BTICardTest.main(BTICardTest.java:14)
Looking for a solution!!
According to the documentation you need to make the library available. There are three ways to do this.
Make your target library available to your Java program. There are
several ways to do this:
The preferred method is to set the jna.library.path system property to
the path to your target library. This property is similar to
java.library.path, but only applies to libraries loaded by JNA.
Change the appropriate library access environment variable before
launching the VM. This is PATH on Windows, LD_LIBRARY_PATH on Linux,
and DYLD_LIBRARY_PATH on OSX.
Make your native library available on your classpath, under the path
{OS}-{ARCH}/{LIBRARY}, where {OS}-{ARCH} is JNA's canonical prefix for
native libraries (e.g. win32-x86, linux-amd64, or darwin). If the
resource is within a jar file it will be automatically extracted when
loaded.

UnsatisfiedLinkError: no opencv_java249 in java.library.path

Running into some problems making a piece of code run on my mac.
Had someone write me an image analysis java app but I keep getting this error when trying to run it on netbeans.
run: Exception in thread "main" java.lang.UnsatisfiedLinkError: no
opencv_java249 in java.library.path at
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) at
java.lang.Runtime.loadLibrary0(Runtime.java:870) at
java.lang.System.loadLibrary(System.java:1119) at
image.prossing.Test.main(Test.java:28) Java Result: 1 BUILD SUCCESSFUL
(total time: 0 seconds)
Have the netbeans project, and added the necessary jar files as libraries. The programmer told me to download the correct OpenCV version and copy the opencv.dll file to my java/jre/bin folder. But I cannot find the dll file or the java/jre folder.
I know most programming happens on windows for a reason. Hope someone can help me resolve this issue and run this application on my mac.
Here is the first part of the code, the part that is most probably creating the error:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package image.prossing;
/**
*
* #author Dumith Salinda
*/
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import static org.opencv.core.Core.FONT_HERSHEY_SIMPLEX;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
public class Test {
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Sorry if it's not that clear, let me know what info to add if something is missing or not clear.
Would truly appreciate any help you could give. Sincerely
Meir Warcel
Look into your OpenCV directory;
For an example this; (installed using brew install opencv3 --with-java --with-python3)
/usr/local/Cellar/opencv3/XXX/share/OpenCV/java
You will see;
libopencv_javaXXX.so opencv-XXX.jar
Now that you already have OpenCV's native library for Java (libopencv_javaXXX.so) compiled with you, the only thing left is, mac's dynamic library.
Link libopencv_javaXXX.so to libopencv_javaXXX.dylib;
ln -s libopencv_javaXXX.so libopencv_javaXXX.dylib
Now add /usr/local/Cellar/opencv3/XXX/share/OpenCV/java as Native Library Locations in IntelliJ or something similar in Eclipse.
Or add this to your JVM arguments;
-Djava.library.path=/usr/local/Cellar/opencv3/XXX/share/OpenCV/java
On a mac running OSX Yosemite, I dropped the libopencv_java2412.dylib file into /Library/Java/Extensions and it worked.
After you build opencv, the libopencv_java2412.dylib is generated in /build/lib.
After Spending a lots of time , and using different suggestions from StackOverflow I managed to get solution for windows. but I am adding a solution for mac as well. hope it should work.
Load your lib as per your system configuration.
private static void loadLibraries() {
try {
InputStream in = null;
File fileOut = null;
String osName = System.getProperty("os.name");
String opencvpath = System.getProperty("user.dir");
if(osName.startsWith("Windows")) {
int bitness = Integer.parseInt(System.getProperty("sun.arch.data.model"));
if(bitness == 32) {
opencvpath=opencvpath+"\\opencv\\x86\\";
}
else if (bitness == 64) {
opencvpath=opencvpath+"\\opencv\\x64\\";
} else {
opencvpath=opencvpath+"\\opencv\\x86\\";
}
}
else if(osName.equals("Mac OS X")){
opencvpath = opencvpath+"Your path to .dylib";
}
System.out.println(opencvpath);
System.load(opencvpath + Core.NATIVE_LIBRARY_NAME + ".dll");
} catch (Exception e) {
throw new RuntimeException("Failed to load opencv native library", e);
}
}
2.now use this method as per your need
public static void main(String[] args) {
loadLibraries();
}
Building on Harsh Vakharia's answer i tried installing OpenCV on my mac with macports:
sudo port install opencv +java
ls /opt/local/share/OpenCV/java
libopencv_java343.dylib opencv-343.jar
To use this library I was hoping to be able to modify the library path at runtime which was discussed in
Adding new paths for native libraries at runtime in Java
And ended up with the following helper class and unit test. The code is now part of the
Self Driving RC-Car open Source project in which I am a comitter.
JUnit Test
/**
* #see <a href=
* 'https://stackoverflow.com/questions/27088934/unsatisfiedlinkerror-no-opencv-java249-in-java-library-path/35112123#35112123'>OpenCV
* native libraries</a>
* #throws Exception
*/
#Test
public void testNativeLibrary() throws Exception {
if (debug)
System.out.println(String.format("trying to load native library %s",
Core.NATIVE_LIBRARY_NAME));
assertTrue(NativeLibrary.getNativeLibPath().isDirectory());
assertTrue(NativeLibrary.getNativeLib().isFile());
NativeLibrary.load();
}
NativeLibrary
package com.bitplan.opencv;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.opencv.core.Core;
/**
* load OpenCV NativeLibrary properly
*/
public class NativeLibrary {
protected static File nativeLibPath = new File("../lib");
/**
* get the native library path
*
* #return the file for the native library
*/
public static File getNativeLibPath() {
return nativeLibPath;
}
/**
* set the native library path
*
* #param pNativeLibPath
* - the library path to use
*/
public static void setNativeLibPath(File pNativeLibPath) {
nativeLibPath = pNativeLibPath;
}
/**
* get the current library path
*
* #return the current library path
*/
public static String getCurrentLibraryPath() {
return System.getProperty("java.library.path");
}
/**
* Adds the specified path to the java library path
*
* #param pathToAdd
* the path to add
* #throws Exception
* #see <a href=
* 'https://stackoverflow.com/questions/15409223/adding-new-paths-for-native-libraries-at-runtime-in-java'>Stackoverflow
* question how to add path entry to native library search path at
* runtime</a>
*/
public static void addLibraryPath(String pathToAdd) throws Exception {
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
usrPathsField.setAccessible(true);
// get array of paths
final String[] paths = (String[]) usrPathsField.get(null);
// check if the path to add is already present
for (String path : paths) {
if (path.equals(pathToAdd)) {
return;
}
}
// add the new path
final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
newPaths[newPaths.length - 1] = pathToAdd;
usrPathsField.set(null, newPaths);
}
public static File getNativeLib() {
File nativeLib = new File(getNativeLibPath(),
"lib" + Core.NATIVE_LIBRARY_NAME + ".dylib");
return nativeLib;
}
/**
* load the native library by adding the proper library path
*
* #throws Exception
* - if reflection access fails (e.g. in Java9/10)
*/
public static void load() throws Exception {
addLibraryPath(getNativeLibPath().getAbsolutePath());
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
}
Exception is occurring from below line of code:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Your program is trying to load a native library by the name of argument in call to loadLibrary method, which it is not able to locate. Make sure that native library (opencv.dll) is placed at one of the locations present in java.library.path system property as JVM looks at these locations for loading any native library (which might not contain 'java/jre/bin').
You can print java.library.path in your program like below:
System.out.println(System.getProperty("java.library.path"));
You cannot just put Windows library (dll file) on Mac and have it running - you need to compile the library for Mac first (or get Mac version of the library).
Please see here for tips on how to do it:
.dll Equivalent on Mac OS X
How do third-party libraries work in Objective-C and Xcode?
How to use a Windows DLL with Java in Mac OS X?
Instead of struggling with manual installation of OpenCV libraries I suggest you use OpenCV Java library packaged by OpenPnP (https://github.com/openpnp/opencv) that includes all required DLL.
It does not require additonal steps except of adding it to your build automation tool configuration (Gradle in my case) and adding the following code to load the library:
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
Just add into the path the folder where your opencv_java249.dll is; it would be something like C:\bin\opencv\build\java\x32 or C:\bin\opencv\build\java\x64 depending of your machine architecture. The problem is that java.library.path is actually the path variable.
netebans right klick project chosew properti
chose run, working direktory, click Browser change to opencv folder, release/lib,

JNA to call a DLL without source code from java

I have to call a dll method and I don't have the source code from dll, I was reading about JNI and understood that you should have the source to input the JNI library in the code (.h).
My second shoot is JNA, but I am getting the same error, although you don't have to change anything in DLL.
I created two classes to test:
interface:
package icom;
import com.sun.jna.Library;
public interface IConectorT extends Library {
int StartConector(byte[] conectorStatus, String icomPath);
}
DLL method call:
package icom;
import com.sun.jna.Native;
public class ConectorTJna {
public static void main(String args[]) {
IConectorT lib = (IConectorT) Native.loadLibrary("ConectorT", IConectorT.class);
int teste = lib.StartConector(null, "C:\\ICOM");
System.out.println("RESULT: " + teste);
}
}
When I call the lib.StartConector method I get this:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error
looking up function 'StartConector': The specified procedure could not
be found. at com.sun.jna.Function.(Function.java:179) at
com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:350) at
com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:330) at
com.sun.jna.Library$Handler.invoke(Library.java:203) at
$Proxy0.StartConector(Unknown Source) at
icom.ConectorTJna.main(ConectorTJna.java:10)
Did you specify path to the library, e.g. using system property?
Here are the details from "Getting Started with JNA" guide:
Make your target library available to your Java program. There are two
ways to do this:
The preferred method is to set the jna.library.path system property to
the path to your target library. This property is similar to
java.library.path, but only applies to libraries loaded by JNA.
Change the appropriate library access environment variable before launching
the VM. This is PATH on Windows, LD_LIBRARY_PATH on Linux, and
DYLD_LIBRARY_PATH on OSX.
Taken from: https://github.com/twall/jna/blob/master/www/GettingStarted.md

JNI native call *prototypes* in their own class/namespace?

I have written JNI wrappers to export the API of a C application (G-WAN) which embeds a JVM. The native calls are implemented in the C application and exported with RegisterNatives().
Ideally I would have a 'gwan' class for the G-WAN API:
import gwan // G-WAN API
public class hello {
public static int jmain(long env, String[] args) {
gwan.xbuf_cat(gwan.get_reply(env), "Hello World");
return 200; // HTTP status (200:'OK')
}
}
I would like to do something like the "#import gwan" above to import the native call prototypes, but currently I only have the following (which works):
public class hello {
public static int jmain(long env, String[] args) {
gwan_xbuf_cat(gwan_get_reply(env), "Hello World");
return 200; // HTTP status (200:'OK')
}
public static native long gwan_get_reply(long env);
public static native void gwan_xbuf_cat(long ctx, String str);
}
Again, the implementation of the native calls in made in the G-WAN executable (not in a Java class stored on disk).
Because the G-WAN API is quite large, I would like to have the native call prototypes in their own 'gwan' class (or namespace) if possible (like in the first hello example above).
Any suggestion about how to do that?
(please post Java or JNI code because I am not a Java expert)
Disclamer: I am involved in the development of this project.
I would suggest that you read following paper on JNI from Sun now Oracle
http://java.sun.com/docs/books/jni/html/jniTOC.html
And after that it should be understandable but some pseudocode and its not tested would be to move the two gwanapi calls into its own file named gwanapi.java
public class gwanapi {
public static native long get_reply(long answer);
public static native void xbuf_cat(long ctx,String str);
}
then you compile that file with javac gwanapi.java -> output: gwanapi.class
you type javah -jni for the c/c++ header implementation:
javah -jni gwanapi
the next you should in your hello java class is to call static{ System.loadLibrary("gwanapi");}
Pseudo code and NOT tested
public class hello{
static{
System.loadLibrary("gwanapi");
}
public static int jmain(long env,String args[]){
gwanapi.xbuf_cat(gwanapi.get_reply(env),"Hello World!");
return 200;
}
}
and you should be good to go.
But I might have missed a point or two but I think this is the smallest amount of work you should do.
Oh by the way http://en.wikipedia.org/wiki/Java_Native_Interface is also some form of source for JNI calls and how it works and lead you to more sites with more information.
Thanks
Being a C programmer, I have had to read the C source code of the JVM to find that Java remaps Class (path) names with dots instead of slashes.
Since the G-WAN directory hierarchy uses IP addresses to define listeners and virtual hosts (192.168.10.10_80/#domain.com/csp), those dots were confusing the FindClass() JNI call, making it fail to find the classes.
I also found that the classpath path separator is a ":" for Unix and a ";" for Windows. That was not the cause of my problem, but it might cause the same issue.
Finally, I stopped using the GCJ compiler's JVM because it does not support formating doubles (since at least 2006). Using either OpenJDK or the SUN/ORACLE JVM works as expected.
All works fine now. I post all this here just in case it may help others.

Categories

Resources