Come creare un file JAR che include file DLL?
Domanda
Ho acquistato una libreria Java di terze parti che include un file JAR e due file DLL. Ho scritto il mio programma Java che richiama il file JAR di terze parti. Ora la mia domanda è come posso impacchettare tutto il mio codice in un singolo file JAR che include tutto il mio codice, JAR e DLL di terze parti?
So che SWT è un caso del genere. Il swt.jar
include i file dll, ma non so come farlo e come farlo funzionare correttamente.
Soluzione
Basta imballarlo ovunque nel vaso. Una cosa che devi tenere a mente però - prima di poter usare le DLL devi estrarle effettivamente dal JAR e scaricarle da qualche parte sul disco rigido altrimenti non sarai in grado di caricarle
Quindi, fondamentalmente, ho fatto un progetto JNI per il cliente in cui userò un tale vaso impacchettato in guerra. Tuttavia - prima di eseguire qualsiasi metodo nativo vorrei ottenere la DLL come risorsa e scriverla sul disco nella directory temporanea. Quindi eseguivo il codice di inizializzazione regolare in cui la mia DLL è impostata nella stessa posizione in cui ho appena scritto la DLL
Oh, e per ogni evenienza: non c'è niente di speciale nel confezionare dll o qualsiasi altro file in jar. È proprio come imballare cose in zip
Ecco un po 'di codice che ho appena estratto
public class Foo {
private static final String LIB_BIN = "/lib-bin/";
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private final static String ACWRAPPER = "acwrapper";
private final static String AAMAPI = "aamapi51";
private final static String LIBEAU = "libeay32";
static {
logger.info("Loading DLL");
try {
System.loadLibrary(ACWRAPPER);
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, ACWRAPPER);
loadLib(path, AAMAPI);
loadLib(path, LIBEAU);
}
/**
* 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) {
throw new ACCoreException("Failed to load required DLL", e);
}
}
// blah-blah - more stuff
}
Altri suggerimenti
Utilizza http://www.jdotsoft.com/JarClassLoader.php che potrebbe caricare DLL e JAR di un altro JAR con annidamento illimitato. Ad esempio, DLL potrebbe trovarsi in JAR che si trova in un altro JAR root. Tutte le DLL e le JAR vengono caricate come se fossero in un percorso di classe o di libreria.