Categories
dll jar java packaging swt

How to make a JAR file that includes DLL files?

75

I bought a third-party Java library which includes a JAR file and two DLL files. I wrote my own Java program which invoke the third-party JAR file. Now my question is how can I package all my code into a single JAR file which include all my code and the third-party JAR and DLLs?

I know SWT is such a case. The swt.jar includes dll files, but I don’t know how to do this and how to make it work properly.

    89

    Just package it anywhere in the jar. One thing you have to keep in mind though – before you can use the DLLs you need to actually extract these from the JAR and dump these on the hard disk somewhere otherwise you won’t be able to load these

    So basically – I did JNI project for the client where I will use such jar packaged within the war. However – before running any native methods I would get the DLL as a resource and write it to the disc into temp directory. Then I would run regular initialization code where my DLL is set to the same location I just wrote DLL to

    Oh, and just in case: there’s nothing special about packaging dll or any other file into jar. It’s just like packaging stuff into zip

    Here’s some code I just digged out

    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") + "https://stackoverflow.com/" + 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
    }
    

    9

    • 8

      A word of caution on this approach – be sure you clean up the temp files. If you re-use the same path each time, consider what happens if multiple applications use your JAR (one will fail if the other already has a lock on the temp file). Just be careful – sometimes it’s easier to deploy the JAR and DLLs separately.

      – Kevin Day

      Oct 24, 2009 at 5:50

    • 9

      One thing to keep in mind: I was using JNI DLLs that were dependent on other DLLs. I included all DLLs inside a jar and used the code above to unpack. But I was getting java.lang.UnsatisfiedLinkError exceptions saying “Can’t find dependent libraries”. The problem is that you must call System.load() on the DLLs in order such that dependent DLLs are loaded first.

      May 24, 2010 at 21:27

    • 1

      Can you tell me in the method loadLib(). you have mentioned ACWrapper.class. Can you tell me what class is this. I mean related to your project? As i need to know how to extract the DLL from the war.

      Sep 16, 2013 at 9:30

    • 1

      Just a class in the same directory as the DLL. The class you use determines where getResourceAsStream checks for the resource.

      – Joanis

      Jun 11, 2015 at 15:49

    • 1

      A more robust loading method would be System.load(fileOut.getAbsolutePath());

      Oct 27, 2016 at 8:02

    7

    Use http://www.jdotsoft.com/JarClassLoader.php which could load DLLs and JARs from another JAR with unlimited nesting. For example, DLL could be in JAR which is in another root JAR. All DLLs and JARs are loaded like they are in a classpath or library path.

    3

    • 31

      Note to others: License is GPLv3, which substantially limits applicability.

      Nov 3, 2011 at 19:24

    • 5

      Also note: This class loader unpacks all nested jars into a temporary directory. So it works like the first answer. The native libs are unpacked only if needed.

      – drzymala

      Feb 14, 2013 at 17:15


    • 2

      Commercial license available.

      – drzymala

      Feb 14, 2013 at 17:25