I've been looking for in the forum questions related with my issue, but I didn't found anything. Any help with this will be appreciated.
I have an application in Java, using IntelliJ, which has, among others, the library RXTXcomm.jar, which comes with a native library with it, rxtxSerial.dll, both in separated files.
I have used this libraries without any issue in my project, by setting properly the dependency of the RXTXcomm.jar library and setting as Native Library Location the rxtxSerial.dll in the Dependencies section of the Project Structure.
The problem comes when I want to generate an artifact of my project. I've created many artifacts with different projects, but is the first time I have to add to the artifact a library with a native .dll library with it. From the Project Structure/Artifacts I double-click over the RXTXcomm.jar as I do in the Project Structure/Modules/Dependencies section to add the rxtxSerial.dll, but of course it doesn't works. I've tried to add the .dll native library to the artifact as any other .jar library I've added before, but it doesn't works. When I run my artifact, this is the error thrown:
I think that the problem is how I am adding this library to the artifact, but I can't find how to do this searching on the web. If read about the NativeUtils class, but I think this is not what I need here because is more an artifact configuration issue. Here I show you how I have added the RXTXcomm.jar and its native library to make it works from the IDE:
And with this, running the application from the IDE everything works perfectly.
Now here is how I am adding the library and its native to build the artifact:
For sure I am doing something wrong here but can't find what. Which is the proper way to add in my artifact this native library (rxtxSerial.dll) to the RXTXcomm.jar library to not have this exception and make it works?
Any help will be appreciated and if some more info is needed please tell me.
Thanks a lot,
Daniel.
EDIT: Following the advice of @Andrey I tried to load the .dll library in the way it is explained in the link he provided: How to make a JAR file that includes DLL files?, but it seems it doesn't work for me and I don't understand why. Here is the code I've used:
public class Main extends Application {
private static DataBase database= new DataBase();
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private static final String LIB_BIN = "/lib-bin/";
private final static String rxtxSerial = "rxtxSerial";
/**
* Function to launch the application
* @param args .
*/
public static void main(String[] args) {
// Merge the Swing and JavaFX threads - needs Java 8
//System.setProperty("javafx.embed.singleThread", "true");
// Verify that Direct3D is enabled (the default setting), to avoid resize issues.
try {
if (Boolean.valueOf(System.getProperty("sun.java2d.noddraw", "false")) ||
!Boolean.valueOf(System.getProperty("sun.java2d.d3d", "true"))) {
throw new IllegalStateException("Do not change the Direct3D default settings (Windows specific), "
+ "it may cause glitches during frame re-sizing.");
}
Application.launch(args);
} catch (IllegalStateException ex){
ex.printStackTrace();
database.insertSystemErrorLog(Thread.currentThread().getStackTrace()[1].getMethodName(),ex);
}
}
/**
* Function to configure the stage where the view will be added
* @param primaryStage the stage to be configured
*/
@Override
public void start(Stage primaryStage) {
try {
if (!EventQueue.isDispatchThread()) {
throw new IllegalStateException(
"FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
}
loadExternalDllFiles();
//Add Swing view and interface components to the FX frame
SwingNode viewNode = addSwingNodeToFXFrame(primaryStage);
//----------------------------------------------
//Add FX view and interface components to the FX frame
//----------------------------------------------
// Auxiliary panel with provisional content
Accordion auxiliaryPanelFX = new Accordion();
// Do the lay-out using FX
HBox hbox = new HBox(viewNode, auxiliaryPanelFX);
HBox.setHgrow(viewNode, Priority.ALWAYS);
// Show the window
primaryStage.setScene(new Scene(hbox));
primaryStage.setFullScreen(true);
primaryStage.setTitle("FXApp");
primaryStage.setResizable(true);
primaryStage.show();
} catch (IllegalStateException ex){
ex.printStackTrace();
database.insertSystemErrorLog(Thread.currentThread().getStackTrace()[1].getMethodName(),ex);
}
}
private void loadExternalDllFiles() {
logger.info("Loading DLL");
try {
System.loadLibrary(rxtxSerial);
logger.info("DLL is loaded from memory");
} catch (UnsatisfiedLinkError e) {
loadFromJar();
}
}
/**
* When packaged into JAR extracts DLLs, places these into
*/
private static void loadFromJar() {
// we need to put both DLLs to temp dir
String path = "AC_" + new Date().getTime();
loadLib(path, rxtxSerial);
}
/**
* Puts library to temp dir and loads to memory
*/
private static void loadLib(String path, String name) {
name = name + ".dll";
try {
// have to use a stream
InputStream in = ACWrapper.class.getResourceAsStream(LIB_BIN + name);
// always write to different location
File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
logger.info("Writing dll to: " + fileOut.getAbsolutePath());
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
System.load(fileOut.toString());
} catch (Exception e) {
System.out.println("Failed to load required DLL");
}
}
/**
* Function to create a SwingNode with all the components using Swing format
* @param primaryStage_ JavaFX Stage where all the Swing components will be added
* @return The SwingNode already built
*/
private SwingNode addSwingNodeToFXFrame(Stage primaryStage_) {
//Set the initial language of the application
Locale locale = new Locale("en", "GB");
LanguageConfiguration.setLanguageSelected(locale);
LanguageConfiguration.setKeyboardLanguage(LanguageConfiguration.KeyboardLanguage.LATIN);
//Create all interface components and add it to the view
InterfaceControlsManager interfaceControlsManager = new InterfaceControlsManager();
TLspSwingView view = interfaceControlsManager.loadSwingInterfaceControls();
// Wrap the Swing view in an FX node so it can be added to the FX hierarchy
SwingNode viewNode = new SwingNode();
viewNode.setContent(view.getHostComponent());
// Clean-up the view when the window is closed
primaryStage_.setOnCloseRequest(event -> view.destroy());
return viewNode;
}
When I call to loadExternalDllFiles();
I start to load the .dll file (rxtxSerial.dll), and it seems that it is being added properly when I see the information printed in my console, where the message "DLL is loaded from memory" is printed. After it is printed, I am getting the same error of the picture I've uploaded before. Here is what I am getting now:
Notice that the .jar library I want to add, RXTXcomm.jar, which allows me to read GPS frames, and its native library, rxtxSerial.dll, are in separated files, so the .dll is not package inside the .jar I think. See the image below of what the artifact has in its folder when it is created with the artifact configuration I show in the picture above:
Sorry for the lenght of the question. I am trying to put as many information I can because this is getting me crazy...