I'm working on a project for school using JNI. In a nutshell, I have gotten the first part working using the shared library and JNI, but the second part (which refers to the same library) gives an UnsatisfiedLinkError every time I try to run the code. My professor and TAs are all unable to figure out this problem and I have been trying to debug it for over a week now.
The first part is a .java program that will be executed independently, given a file of integers and a frequency, it should call native code in C to compute a direct fourier transform and return a value given a frequency. In java, I stored these ints into an array and passed the array to JNI to compute the DFT in C. This returns a single int value and works like a charm.
For the second part, we have created a gui interface which loads the JNI library and takes in a .wav file or a file of our own format. This gui is required to calculate the frequency of a file when selected from a file chooser. Since the .wav files (and the other type) have header information as well as binary data, rather than integer numbers as in the first part, my strategy is to pass the filename (as a string) to JNI so that my native code can dissect the int values into an array itself and then calculate the frequency of the file. My gui is complete, and the action event of selecting a file from the chooser is supposed to call the JNI code and return the frequency of the file. Interestingly, the code compiles in linux and loads the library successfully, but crashes with this link error when the file is chosen and the native code is supposed to be called using the file chooser. I am at a complete and total frustrated defeat. Any ideas?
HERE IS THE HEADER FILE GENERATED BY JNI
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class dft */
#ifndef _Included_dft
#define _Included_dft
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: dft
* Method: computeDFT
* Signature: ([III)I
*/
JNIEXPORT jint JNICALL Java_dft_computeDFT
(JNIEnv *, jobject, jintArray, jint, jint);
/*
* Class: dft
* Method: computeFileDFT
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_dft_computeFileDFT
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
HERE IS THE CODE THAT WORKS
public class dft
{
private native int computeDFT(int[] nums, int count, int freq);
private native int computeFileDFT(String fileName);
static
{
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* SYSTEM LOAD LIBRARY PATH BELOW
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
System.loadLibrary("dft");
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException
{
File infile;
Scanner sc = null;
dft dft = new dft();
int count = 0;
int[] data = new int[4096];
//code that reads the file and puts the content into an array called 'data'
//the args[1] below is the specified frequency to be calculated in JNI
int dftValue = dft.computeDFT(data, count, Integer.parseInt(args[1]));
System.out.println(dftValue);
}
HERE IS THE PROBLEM CODE
private native int computeFileDFT(String fileName);
static
{
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* SYSTEM LOAD LIBRARY PATH BELOW
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
System.loadLibrary("dft");
System.out.println("loaded successfully");
}
//imagine more code here creating a JPanel object,
//adding a bunch of stuff to it, etc.
//One key item that is added is a button,
//which when pressed opens a JFileChooser object,
//below you will see my implementation of the
//ActionListener which listens to the button and is
//supposed to execute the native code when the file is chosen.
private class TunerButtonListener implements ActionListener
{
//@Override
public void actionPerformed(ActionEvent event)
{
int returnVal = dialog.showOpenDialog(fileButton);
if(returnVal == JFileChooser.APPROVE_OPTION)
{
currentFileName = dialog.getSelectedFile().getName();
currentFilePath = dialog.getSelectedFile().getPath();
message.setText(currentFileName);
int val = computeFileDFT(currentFilePath);
//more code goes here that does more stuff
THE FULL ERROR MESSAGE AND STACK
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: TunerPanel.computeFileDFT(Ljava/lang/String;)I
at TunerPanel.computeFileDFT(Native Method)
at TunerPanel$TunerButtonListener.actionPerformed(TunerPanel.java:167)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
at java.awt.Component.processMouseEvent(Component.java:6389)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3268)
at java.awt.Component.processEvent(Component.java:6154)
at java.awt.Container.processEvent(Container.java:2045)
at java.awt.Component.dispatchEventImpl(Component.java:4750)
at java.awt.Container.dispatchEventImpl(Container.java:2103)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4633)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4297)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4227)
at java.awt.Container.dispatchEventImpl(Container.java:2089)
at java.awt.Window.dispatchEventImpl(Window.java:2518)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:672)
at java.awt.EventQueue.access$400(EventQueue.java:96)
at java.awt.EventQueue$2.run(EventQueue.java:631)
at java.awt.EventQueue$2.run(EventQueue.java:629)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:116)
at java.awt.EventQueue$3.run(EventQueue.java:645)
at java.awt.EventQueue$3.run(EventQueue.java:643)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:642)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)