Resource won’t load when exported as a JAR

Tags: , , , ,



Using the following code to set a system property:


    ClassLoader classLoader = StartMain.class.getClassLoader();

    URL resource = classLoader.getResource("com/myname/lib/chromedriver/chromedriver.exe");

    File f = new File("Driver");

    if (!f.exists()) {

        f.mkdirs();

    }

    File chromeDriver = new File("Driver" + File.separator + "chromedriver.exe");

    if (!chromeDriver.exists()) {

        chromeDriver.createNewFile();

        org.apache.commons.io.FileUtils.copyURLToFile(resource, chromeDriver);

    }

This works perfectly when I run my application configuration in my IDE, IntelliJ. However, when I build a JAR and attempt to use this outside of IntelliJ, the resource URL returns as null. Why is this so?

Answer

Going via your classloader is risky. It probably doesn’t explain your problem but it might; in any case, this alternative way to do it is shorter, simpler, more idiomatic, works in all places your take works, and works in more places to boot:

The best way to fetch resources like this is like so:

StartMain.class.getResource("/com/myname/lib/chromedriver/chromedriver.exe");

Note that this one starts with a slash! This style goes relative to your own class file location (your package, basically) if you don’t.

Either form will look for the entry:

/com/myname/lib/chromedriver/chromedriver.exe

inside the same jar that StartMain.class lives. If it is not there, then this obviously won’t work – fix your build so that it is included. At ‘runtime’ some folder may be on the classpath that would resolve this file; if that folder is then not folded into you jar during the build, that would explain why it works within the IDE but not elsewhere.

NB: You generally don’t need any apache utils. For example, there’s InputStream’s transferTo which can make this a one-liner too (fetch getResourceAsStream instead).



Source: stackoverflow