Search code examples
javaurlfilesystemsclasspathclassloader

Resource won't load when exported as a JAR


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?


Solution

  • 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).