2009-10-23 15 views
59

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 e il JAR e le DLL di terze parti?Come creare un file JAR che include file DLL?

Lo so SWT è un caso del genere. Lo swt.jar include i file dll, ma non so come farlo e come farlo funzionare correttamente.

risposta

68

Basta impacchettarlo ovunque nel barattolo. Una cosa da tenere a mente però - prima di poter usare le DLL è necessario estrarle dal JAR e scaricarle da qualche parte sul disco rigido altrimenti non sarà possibile caricare queste

Quindi fondamentalmente - Ho fatto un progetto JNI per il cliente in cui userò tale barattolo confezionato all'interno della guerra. Tuttavia, prima di eseguire qualsiasi metodo nativo, otterrei la DLL come risorsa e la scriverò sul disco nella directory temp. Quindi eseguirò il normale codice di inizializzazione dove la mia DLL è impostata nella stessa posizione Ho appena scritto DLL su

Oh, e nel caso in cui: non c'è niente di speciale sulla confezione dll o qualsiasi altro file in jar. E 'proprio come il confezionamento di roba nel zip

Ecco alcuni codice che ho appena scavato fuori

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 
} 
+7

Una parola di cautela su questo approccio: accertati di aver pulito i file temporanei. Se si riutilizza lo stesso percorso ogni volta, considerare ciò che accade se più applicazioni utilizzano il JAR (una fallirà se l'altra ha già un blocco sul file temporaneo). Basta fare attenzione: a volte è più semplice distribuire separatamente JAR e DLL. –

+0

Il codice può essere modificato per sovrascrivere il file precedentemente installato. Nel mio caso - questa era un'app web che non verrà riciclata frequentemente, ma davvero - se copi il codice "così com'è" riceverai una nuova copia di DLL ogni volta che lo esegui. – Bostone

+7

Una cosa da tenere a mente: I stava usando DLL JNI che dipendevano da altre DLL. Ho incluso tutte le DLL all'interno di un barattolo e ho utilizzato il codice sopra per decomprimere. Ma stavo ottenendo eccezioni java.lang.UnsatisfiedLinkError dicendo "Impossibile trovare librerie dipendenti". Il problema è che è necessario chiamare System.load() sulle DLL in modo tale che le DLL dipendenti vengano caricate per prime. –

6

Usa http://www.jdotsoft.com/JarClassLoader.php che potrebbe caricare DLL e JAR da un altro vaso con nidificazione illimitato. Ad esempio, DLL potrebbe essere in JAR che si trova in un altro JAR di root. Tutte le DLL e i JAR vengono caricati come se si trovassero in un percorso di classe o in un percorso di libreria.

+23

Nota per gli altri: la licenza è GPLv3, che limita sostanzialmente l'applicabilità. –

+4

Nota: questo programma di caricamento classe decomprime tutti i jar annidati in una directory temporanea. Quindi funziona come la prima risposta. Le librerie native vengono decompresse solo se necessario. – drzymala

+1

Licenza commerciale disponibile. – drzymala